# This file is part of Androguard.
#
# Copyright (C) 2012, Anthony Desnos <desnos at t0t0.fr>
# All rights reserved.
#
# Androguard is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Androguard is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Androguard.  If not, see <http://www.gnu.org/licenses/>.

from struct import pack, unpack, calcsize
from collections import namedtuple
import re
import zipfile
import StringIO
import os

from CheckProtect.androguard.core import bytecode
from CheckProtect.androguard.core.bytecode import SV, SVs





######################################################## JAR FORMAT ########################################################
class JAR:
    def __init__(self, filename, raw=False):
        self.filename = filename

        if raw == True:
            self.__raw = filename
        else:
            fd = open(filename, "rb")
            self.__raw = fd.read()
            fd.close()

        self.zip = zipfile.ZipFile(StringIO.StringIO(self.__raw))

    def get_classes(self):
        l = []
        for i in self.zip.namelist():
            if ".class" in i:
                l.append((i, self.zip.read(i)))

        return l


    def show(self):
        print self.zip.namelist()

######################################################## CLASS FORMAT ########################################################

# Special functions to manage more easily special arguments of bytecode
def special_F0(x):
    return [i for i in x]


def special_F0R(x):
    return [x]


def special_F1(x):
    return (x[0] << 8) | x[1]


def special_F1R(x):
    return [(x & 0xFF00) >> 8, x & 0x00FF]


def special_F2(x):
    v = ((x[0] << 8) | x[1])
    if v > 0x7FFF:
        v = (0x7FFF & v) - 0x8000

    return v


def special_F2R(x):
    val = x & 0xFFFF
    return [(val & 0xFF00) >> 8, val & 0x00FF]


def special_F3(x):
    val = (x[0] << 24) | (x[1] << 16) | (x[2] << 8) | x[3]
    if val > 0x7fffffff:
        val = (0x7fffffff & val) - 0x80000000
    return val


def special_F3R(x):
    val = x & 0xFFFFFFFF
    return [(val & 0xFF000000) >> 24, (val & 0x00FF0000) >> 16, (val & 0x0000FF00) >> 8, val & 0x000000FF]


def special_F4(x):
    return [(x[0] << 8) | x[1], x[2]]


def special_F4R(x):
    pass


def specialSwitch(x):
    return x


FD = {"B": "byte",
      "C": "char",
      "D": "double",
      "F": "float",
      "I": "int",
      "J": "long",
      "S": "short",
      "Z": "boolean",
      "V": "void",
}


def formatFD(v):
    #print v, "--->",
    l = []

    i = 0
    while i < len(v):
        if v[i] == "L":
            base_object = ""
            i = i + 1
            while v[i] != ";":
                base_object += v[i]
                i = i + 1
            l.append(os.path.basename(base_object))
        elif v[i] == "[":
            z = []
            while v[i] == "[":
                z.append("[]")
                i = i + 1

            l.append([FD[v[i]], z])
        else:
            l.append(FD[v[i]])
        i = i + 1

        #print l
    return l


def TableSwitch(idx, raw_format):
    r_buff = []
    r_format = ">"

    idx = idx + 1

    n = 0
    if idx % 4:
        n = 4 - (idx % 4)

    for i in range(0, n):
        r_buff.append("bytepad%d" % i)
        r_format += "B"

    r_buff.extend(["default", "low", "high"])
    r_format += "LLL"

    idx = 1 + n + 4

    low = unpack('>L', raw_format[idx: idx + 4])[0]
    idx = idx + 4
    high = unpack('>L', raw_format[idx: idx + 4])[0]

    for i in range(0, high - low + 1):
        r_buff.append("offset%d" % i)
        r_format += "L"

    return specialSwitch, specialSwitch, r_buff, r_format, None


def LookupSwitch(idx, raw_format):
    r_buff = []
    r_format = ">"

    idx = idx + 1

    n = 0
    if idx % 4:
        n = 4 - (idx % 4)

    for i in range(0, n):
        r_buff.append("bytepad%d" % i)
        r_format += "B"

    r_buff.extend(["default", "npairs"])
    r_format += "LL"

    idx = 1 + n + 4
    for i in range(0, unpack('>L', raw_format[idx: idx + 4])[0]):
        r_buff.extend(["match%d" % i, "offset%d" % i])
        r_format += "LL"

    return specialSwitch, specialSwitch, r_buff, r_format, None

# The list of java bytecodes, with their value, name, and special functions !
JAVA_OPCODES = {
    0x32: ["aaload"],
    0x53: ["aastore"],
    0x1: ["aconst_null"],
    0x19: ["aload", "index:B", special_F0, special_F0, None],
    0x2a: ["aload_0"],
    0x2b: ["aload_1"],
    0x2c: ["aload_2"],
    0x2d: ["aload_3"],
    0xbd: ["anewarray", "indexbyte1:B indexbyte2:B", special_F1, special_F1R, "get_class"],
    0xb0: ["areturn"],
    0xbe: ["arraylength"],
    0x3a: ["astore", "index:B", special_F0, special_F0, None],
    0x4b: ["astore_0"],
    0x4c: ["astore_1"],
    0x4d: ["astore_2"],
    0x4e: ["astore_3"],
    0xbf: ["athrow"],
    0x33: ["baload"],
    0x54: ["bastore"],
    0x10: ["bipush", "byte:B", special_F0, special_F0R, None],
    0x34: ["caload"],
    0x55: ["castore"],
    0xc0: ["checkcast", "indexbyte1:B indexbyte2:B", special_F1, special_F1R, None],
    0x90: ["d2f"],
    0x8e: ["d2i"],
    0x8f: ["d2l"],
    0x63: ["dadd"],
    0x31: ["daload"],
    0x52: ["dastore"],
    0x98: ["dcmpg"],
    0x97: ["dcmpl"],
    0xe: ["dconst_0"],
    0xf: ["dconst_1"],
    0x6f: ["ddiv"],
    0x18: ["dload", "index:B", special_F0, special_F0, None],
    0x26: ["dload_0"],
    0x27: ["dload_1"],
    0x28: ["dload_2"],
    0x29: ["dload_3"],
    0x6b: ["dmul"],
    0x77: ["dneg"],
    0x73: ["drem"],
    0xaf: ["dreturn"],
    0x39: ["dstore", "index:B", special_F0, special_F0, None],
    0x47: ["dstore_0"],
    0x48: ["dstore_1"],
    0x49: ["dstore_2"],
    0x4a: ["dstore_3"],
    0x67: ["dsub"],
    0x59: ["dup"],
    0x5a: ["dup_x1"],
    0x5b: ["dup_x2"],
    0x5c: ["dup2"],
    0x5d: ["dup2_x1"],
    0x5e: ["dup2_x2"],
    0x8d: ["f2d"],
    0x8b: ["f2i"],
    0x8c: ["f2l"],
    0x62: ["fadd"],
    0x30: ["faload"],
    0x51: ["fastore"],
    0x96: ["fcmpg"],
    0x95: ["fcmpl"],
    0xb: ["fconst_0"],
    0xc: ["fconst_1"],
    0xd: ["fconst_2"],
    0x6e: ["fdiv"],
    0x17: ["fload", "index:B", special_F0, special_F0, None],
    0x22: ["fload_0"],
    0x23: ["fload_1"],
    0x24: ["fload_2"],
    0x25: ["fload_3"],
    0x6a: ["fmul"],
    0x76: ["fneg"],
    0x72: ["frem"],
    0xae: ["freturn"],
    0x38: ["fstore", "index:B", special_F0, special_F0, None],
    0x43: ["fstore_0"],
    0x44: ["fstore_1"],
    0x45: ["fstore_2"],
    0x46: ["fstore_3"],
    0x66: ["fsub"],
    0xb4: ["getfield", "indexbyte1:B indexbyte2:B", special_F1, special_F1R, "get_field"],
    0xb2: ["getstatic", "indexbyte1:B indexbyte2:B", special_F1, special_F1R, "get_field", "get_field_index"],
    0xa7: ["goto", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None],
    0xc8: ["goto_w", "branchbyte1:B branchbyte2:B branchbyte3:B branchbyte4:B", special_F3, special_F3R, None],
    0x91: ["i2b"],
    0x92: ["i2c"],
    0x87: ["i2d"],
    0x86: ["i2f"],
    0x85: ["i2l"],
    0x93: ["i2s"],
    0x60: ["iadd"],
    0x2e: ["iaload"],
    0x7e: ["iand"],
    0x4f: ["iastore"],
    0x2: ["iconst_m1"],
    0x3: ["iconst_0"],
    0x4: ["iconst_1"],
    0x5: ["iconst_2"],
    0x6: ["iconst_3"],
    0x7: ["iconst_4"],
    0x8: ["iconst_5"],
    0x6c: ["idiv"],
    0xa5: ["if_acmpeq", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None],
    0xa6: ["if_acmpne", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None],
    0x9f: ["if_icmpeq", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None],
    0xa0: ["if_icmpne", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None],
    0xa1: ["if_icmplt", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None],
    0xa2: ["if_icmpge", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None],
    0xa3: ["if_icmpgt", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None],
    0xa4: ["if_icmple", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None],
    0x99: ["ifeq", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None],
    0x9a: ["ifne", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None],
    0x9b: ["iflt", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None],
    0x9c: ["ifge", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None],
    0x9d: ["ifgt", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None],
    0x9e: ["ifle", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None],
    0xc7: ["ifnonnull", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None],
    0xc6: ["ifnull", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None],
    0x84: ["iinc", "index:B const:B", special_F0, special_F0, None],
    0x15: ["iload", "index:B", special_F0, special_F0, None],
    0x1a: ["iload_0"],
    0x1b: ["iload_1"],
    0x1c: ["iload_2"],
    0x1d: ["iload_3"],
    0x68: ["imul"],
    0x74: ["ineg"],
    0xc1: ["instanceof", "indexbyte1:B indexbyte2:B", special_F2, special_F2R, None],
    0xb9: ["invokeinterface", "indexbyte1:B indexbyte2:B count:B null:B", special_F1, special_F1R, "get_interface",
           "get_interface_index"],
    0xb7: ["invokespecial", "indexbyte1:B indexbyte2:B", special_F1, special_F1R, "get_method", "get_method_index"],
    0xb8: ["invokestatic", "indexbyte1:B indexbyte2:B", special_F1, special_F1R, "get_method", "get_method_index"],
    0xb6: ["invokevirtual", "indexbyte1:B indexbyte2:B", special_F1, special_F1R, "get_method", "get_method_index"],
    0x80: ["ior"],
    0x70: ["irem"],
    0xac: ["ireturn"],
    0x78: ["ishl"],
    0x7a: ["ishr"],
    0x36: ["istore", "index:B", special_F0, special_F0, None],
    0x3b: ["istore_0"],
    0x3c: ["istore_1"],
    0x3d: ["istore_2"],
    0x3e: ["istore_3"],
    0x64: ["isub"],
    0x7c: ["iushr"],
    0x82: ["ixor"],
    0xa8: ["jsr", "branchbyte1:B branchbyte2:B", special_F2, special_F2R, None],
    0xc9: ["jsr_w", "branchbyte1:B branchbyte2:B branchbyte3:B branchbyte4:B", special_F3, special_F3R, None],
    0x8a: ["l2d"],
    0x89: ["l2f"],
    0x88: ["l2i"],
    0x61: ["ladd"],
    0x2f: ["laload"],
    0x7f: ["land"],
    0x50: ["lastore"],
    0x94: ["lcmp"],
    0x9: ["lconst_0"],
    0xa: ["lconst_1"],
    0x12: ["ldc", "index:B", special_F0, special_F0R, "get_value"],
    0x13: ["ldc_w", "indexbyte1:B indexbyte2:B", special_F2, special_F2R, None],
    0x14: ["ldc2_w", "indexbyte1:B indexbyte2:B", special_F2, special_F2R, None],
    0x6d: ["ldiv"],
    0x16: ["lload", "index:B", special_F0, special_F0, None],
    0x1e: ["lload_0"],
    0x1f: ["lload_1"],
    0x20: ["lload_2"],
    0x21: ["lload_3"],
    0x69: ["lmul"],
    0x75: ["lneg"],
    0xab: ["lookupswitch", LookupSwitch],
    0x81: ["lor"],
    0x71: ["lrem"],
    0xad: ["lreturn"],
    0x79: ["lshl"],
    0x7b: ["lshr"],
    0x37: ["lstore", "index:B", special_F0, special_F0, None],
    0x3f: ["lstore_0"],
    0x40: ["lstore_1"],
    0x41: ["lstore_2"],
    0x42: ["lstore_3"],
    0x65: ["lsub"],
    0x7d: ["lushr"],
    0x83: ["lxor"],
    0xc2: ["monitorenter"],
    0xc3: ["monitorexit"],
    0xc5: ["multianewarray", "indexbyte1:B indexbyte2:B dimensions:B", special_F4, special_F4R, None],
    0xbb: ["new", "indexbyte1:B indexbyte2:B", special_F1, special_F1R, "get_class", "get_class_index2"],
    0xbc: ["newarray", "atype:B", special_F0, special_F0, "get_array_type"],
    0x0: ["nop"],
    0x57: ["pop"],
    0x58: ["pop2"],
    0xb5: ["putfield", "indexbyte1:B indexbyte2:B", special_F1, special_F1R, "get_field", "get_field_index"],
    0xb3: ["putstatic", "indexbyte1:B indexbyte2:B", special_F1, special_F1R, "get_field", "get_field_index"],
    0xa9: ["ret", "index:B", special_F0, special_F0, None],
    0xb1: ["return"],
    0x35: ["saload"],
    0x56: ["sastore"],
    0x11: ["sipush", "byte1:B byte2:B", special_F1, special_F1R, None],
    0x5f: ["swap"],
    0xaa: ["tableswitch", TableSwitch],
    0xc4: ["wide"], # FIXME
}

# Invert the value and the name of the bytecode
INVERT_JAVA_OPCODES = dict([( JAVA_OPCODES[k][0], k ) for k in JAVA_OPCODES])

# List of java bytecodes which can modify the control flow
BRANCH_JVM_OPCODES = ["goto", "goto_w", "if_acmpeq", "if_icmpeq", "if_icmpne", "if_icmplt", "if_icmpge", "if_icmpgt",
                      "if_icmple", "ifeq", "ifne", "iflt", "ifge", "ifgt", "ifle", "ifnonnull", "ifnull", "jsr",
                      "jsr_w"]

BRANCH2_JVM_OPCODES = ["goto", "goto.", "jsr", "jsr.", "if.", "return", ".return", "tableswitch", "lookupswitch"]

MATH_JVM_OPCODES = {".and": '&',
                    ".add": '+',
                    ".sub": '-',
                    ".mul": '*',
                    ".div": '/',
                    ".shl": '<<',
                    ".shr": '>>',
                    ".xor": '^',
                    ".or": '|',
}

MATH_JVM_RE = []
for i in MATH_JVM_OPCODES:
    MATH_JVM_RE.append((re.compile(i), MATH_JVM_OPCODES[i]))

INVOKE_JVM_OPCODES = ["invoke."]
FIELD_READ_JVM_OPCODES = ["get."]
FIELD_WRITE_JVM_OPCODES = ["put."]

BREAK_JVM_OPCODES = ["invoke.", "put.", ".store", "iinc", "pop", ".return", "if."]

INTEGER_INSTRUCTIONS = ["bipush", "sipush"]


def EXTRACT_INFORMATION_SIMPLE(op_value):
    """Extract information (special functions) about a bytecode"""
    r_function = JAVA_OPCODES[op_value][2]
    v_function = JAVA_OPCODES[op_value][3]
    f_function = JAVA_OPCODES[op_value][4]

    r_format = ">"
    r_buff = []

    format = JAVA_OPCODES[op_value][1]
    l = format.split(" ")
    for j in l:
        operands = j.split(":")

        name = operands[0] + " "
        val = operands[1]

        r_buff.append(name.replace(' ', ''))
        r_format += val

    return ( r_function, v_function, r_buff, r_format, f_function )


def EXTRACT_INFORMATION_VARIABLE(idx, op_value, raw_format):
    r_function, v_function, r_buff, r_format, f_function = JAVA_OPCODES[op_value][1](idx, raw_format)
    return ( r_function, v_function, r_buff, r_format, f_function )


def determineNext(i, end, m):
    #if "invoke" in i.get_name() :
    #    self.childs.append( self.end, -1, ExternalMethod( i.get_operands()[0], i.get_operands()[1], i.get_operands()[2] ) )
    #    self.childs.append( self.end, self.end, self.__context.get_basic_block( self.end + 1 ) )
    if "return" in i.get_name():
        return [-1]
    elif "goto" in i.get_name():
        return [i.get_operands() + end]
    elif "jsr" in i.get_name():
        return [i.get_operands() + end]
    elif "if" in i.get_name():
        return [end + i.get_length(), i.get_operands() + end]
    elif "tableswitch" in i.get_name():
        x = []

        x.append(i.get_operands().default + end)
        for idx in range(0, (i.get_operands().high - i.get_operands().low) + 1):
            off = getattr(i.get_operands(), "offset%d" % idx)

            x.append(off + end)
        return x
    elif "lookupswitch" in i.get_name():
        x = []

        x.append(i.get_operands().default + end)

        for idx in range(0, i.get_operands().npairs):
            off = getattr(i.get_operands(), "offset%d" % idx)
            x.append(off + end)
        return x
    return []


def determineException(vm, m):
    return []


def classToJclass(x):
    return "L%s;" % x


METHOD_INFO = ['>HHHH', namedtuple("MethodInfo", "access_flags name_index descriptor_index attributes_count")]
ATTRIBUTE_INFO = ['>HL', namedtuple("AttributeInfo", "attribute_name_index attribute_length")]
FIELD_INFO = ['>HHHH', namedtuple("FieldInfo", "access_flags name_index descriptor_index attributes_count")]
LINE_NUMBER_TABLE = ['>HH', namedtuple("LineNumberTable", "start_pc line_number")]
EXCEPTION_TABLE = ['>HHHH', namedtuple("ExceptionTable", "start_pc end_pc handler_pc catch_type")]
LOCAL_VARIABLE_TABLE = ['>HHHHH', namedtuple("LocalVariableTable", "start_pc length name_index descriptor_index index")]
LOCAL_VARIABLE_TYPE_TABLE = ['>HHHHH',
                             namedtuple("LocalVariableTypeTable", "start_pc length name_index signature_index index")]

CODE_LOW_STRUCT = ['>HHL', namedtuple("LOW", "max_stack max_locals code_length")]

ARRAY_TYPE = {
    4: "T_BOOLEAN",
    5: "T_CHAR",
    6: "T_FLOAT",
    7: "T_DOUBLE",
    8: "T_BYTE",
    9: "T_SHORT",
    10: "T_INT",
    11: "T_LONG",
}
INVERT_ARRAY_TYPE = dict([( ARRAY_TYPE[k][0], k ) for k in ARRAY_TYPE])

ACC_CLASS_FLAGS = {
    0x0001: ["ACC_PUBLIC", "Declared public; may be accessed from outside its package."],
    0x0010: ["ACC_FINAL", "Declared final; no subclasses allowed."],
    0x0020: ["ACC_SUPER", "Treat superclass methods specially when invoked by the invokespecial instruction."],
    0x0200: ["ACC_INTERFACE", "Is an interface, not a class."],
    0x0400: ["ACC_ABSTRACT", "Declared abstract; may not be instantiated."],
}
INVERT_ACC_CLASS_FLAGS = dict([( ACC_CLASS_FLAGS[k][0], k ) for k in ACC_CLASS_FLAGS])

ACC_FIELD_FLAGS = {
    0x0001: ["ACC_PUBLIC", "Declared public; may be accessed from outside its package."],
    0x0002: ["ACC_PRIVATE", "Declared private; usable only within the defining class."],
    0x0004: ["ACC_PROTECTED", "Declared protected; may be accessed within subclasses."],
    0x0008: ["ACC_STATIC", "Declared static."],
    0x0010: ["ACC_FINAL", "Declared final; no further assignment after initialization."],
    0x0040: ["ACC_VOLATILE", "Declared volatile; cannot be cached."],
    0x0080: ["ACC_TRANSIENT", "Declared transient; not written or read by a persistent object manager."],
}
INVERT_ACC_FIELD_FLAGS = dict([( ACC_FIELD_FLAGS[k][0], k ) for k in ACC_FIELD_FLAGS])

ACC_METHOD_FLAGS = {
    0x0001: ["ACC_PUBLIC", "Declared public; may be accessed from outside its package."],
    0x0002: ["ACC_PRIVATE", "Declared private; accessible only within the defining class."],
    0x0004: ["ACC_PROTECTED", "Declared protected; may be accessed within subclasses."],
    0x0008: ["ACC_STATIC", "Declared static."],
    0x0010: ["ACC_FINAL", "Declared final; may not be overridden."],
    0x0020: ["ACC_SYNCHRONIZED", "Declared synchronized; invocation is wrapped in a monitor lock."],
    0x0100: ["ACC_NATIVE", "Declared native; implemented in a language other than Java."],
    0x0400: ["ACC_ABSTRACT", "Declared abstract; no implementation is provided."],
    0x0800: ["ACC_STRICT", "Declared strictfp; floating-point mode is FP-strict"]
}
INVERT_ACC_METHOD_FLAGS = dict([( ACC_METHOD_FLAGS[k][0], k ) for k in ACC_METHOD_FLAGS])


class CpInfo(object):
    """Generic class to manage constant info object"""

    def __init__(self, buff):
        self.__tag = SV('>B', buff.read_b(1))

        self.__bytes = None
        self.__extra = 0

        tag_value = self.__tag.get_value()
        format = CONSTANT_INFO[tag_value][1]

        self.__name = CONSTANT_INFO[tag_value][0]

        self.format = SVs(format, CONSTANT_INFO[tag_value][2], buff.read(calcsize(format)))

        # Utf8 value ?
        if tag_value == 1:
            self.__extra = self.format.get_value().length
            self.__bytes = SVs(">%ss" % self.format.get_value().length,
                               namedtuple(CONSTANT_INFO[tag_value][0] + "_next", "bytes"),
                               buff.read(self.format.get_value().length))

    def get_format(self):
        return self.format

    def get_name(self):
        return self.__name

    def get_bytes(self):
        return self.__bytes.get_value().bytes

    def set_bytes(self, name):
        self.format.set_value({"length": len(name)})
        self.__extra = self.format.get_value().length
        self.__bytes = SVs(">%ss" % self.format.get_value().length,
                           namedtuple(CONSTANT_INFO[self.__tag.get_value()][0] + "_next", "bytes"), name)

    def get_length(self):
        return self.__extra + calcsize(CONSTANT_INFO[self.__tag.get_value()][1])

    def get_raw(self):
        if self.__bytes != None:
            return self.format.get_value_buff() + self.__bytes.get_value_buff()
        return self.format.get_value_buff()

    def show(self):
        if self.__bytes != None:
            print self.format.get_value(), self.__bytes.get_value()
        else:
            print self.format.get_value()


class MethodRef(CpInfo):
    def __init__(self, class_manager, buff):
        super(MethodRef, self).__init__(buff)

    def get_class_index(self):
        return self.format.get_value().class_index

    def get_name_and_type_index(self):
        return self.format.get_value().name_and_type_index


class InterfaceMethodRef(CpInfo):
    def __init__(self, class_manager, buff):
        super(InterfaceMethodRef, self).__init__(buff)

    def get_class_index(self):
        return self.format.get_value().class_index

    def get_name_and_type_index(self):
        return self.format.get_value().name_and_type_index


class FieldRef(CpInfo):
    def __init__(self, class_manager, buff):
        super(FieldRef, self).__init__(buff)

    def get_class_index(self):
        return self.format.get_value().class_index

    def get_name_and_type_index(self):
        return self.format.get_value().name_and_type_index


class Class(CpInfo):
    def __init__(self, class_manager, buff):
        super(Class, self).__init__(buff)

    def get_name_index(self):
        return self.format.get_value().name_index


class Utf8(CpInfo):
    def __init__(self, class_manager, buff):
        super(Utf8, self).__init__(buff)


class String(CpInfo):
    def __init__(self, class_manager, buff):
        super(String, self).__init__(buff)


class Integer(CpInfo):
    def __init__(self, class_manager, buff):
        super(Integer, self).__init__(buff)


class Float(CpInfo):
    def __init__(self, class_manager, buff):
        super(Float, self).__init__(buff)


class Long(CpInfo):
    def __init__(self, class_manager, buff):
        super(Long, self).__init__(buff)


class Double(CpInfo):
    def __init__(self, class_manager, buff):
        super(Double, self).__init__(buff)


class NameAndType(CpInfo):
    def __init__(self, class_manager, buff):
        super(NameAndType, self).__init__(buff)

    def get_get_name_index(self):
        return self.format.get_value().get_name_index

    def get_name_index(self):
        return self.format.get_value().name_index

    def get_descriptor_index(self):
        return self.format.get_value().descriptor_index


class EmptyConstant:
    def __init__(self):
        pass

    def get_name(self):
        return ""

    def get_raw(self):
        return ""

    def get_length(self):
        return 0

    def show(self):
        pass


CONSTANT_INFO = {
    7: ["CONSTANT_Class", '>BH', namedtuple("CONSTANT_Class_info", "tag name_index"), Class],
    9: ["CONSTANT_Fieldref", '>BHH', namedtuple("CONSTANT_Fieldref_info", "tag class_index name_and_type_index"),
        FieldRef],
    10: ["CONSTANT_Methodref", '>BHH', namedtuple("CONSTANT_Methodref_info", "tag class_index name_and_type_index"),
         MethodRef],
    11: ["CONSTANT_InterfaceMethodref", '>BHH',
         namedtuple("CONSTANT_InterfaceMethodref_info", "tag class_index name_and_type_index"), InterfaceMethodRef],
    8: ["CONSTANT_String", '>BH', namedtuple("CONSTANT_String_info", "tag string_index"), String],
    3: ["CONSTANT_Integer", '>BL', namedtuple("CONSTANT_Integer_info", "tag bytes"), Integer],
    4: ["CONSTANT_Float", '>BL', namedtuple("CONSTANT_Float_info", "tag bytes"), Float],
    5: ["CONSTANT_Long", '>BLL', namedtuple("CONSTANT_Long_info", "tag high_bytes low_bytes"), Long],
    6: ["CONSTANT_Double", '>BLL', namedtuple("CONSTANT_Long_info", "tag high_bytes low_bytes"), Double],
    12: ["CONSTANT_NameAndType", '>BHH', namedtuple("CONSTANT_NameAndType_info", "tag name_index descriptor_index"),
         NameAndType],
    1: ["CONSTANT_Utf8", '>BH', namedtuple("CONSTANT_Utf8_info", "tag length"), Utf8]
}
INVERT_CONSTANT_INFO = dict([( CONSTANT_INFO[k][0], k ) for k in CONSTANT_INFO])
ITEM_Top = 0
ITEM_Integer = 1
ITEM_Float = 2
ITEM_Long = 4
ITEM_Double = 3
ITEM_Null = 5
ITEM_UninitializedThis = 6
ITEM_Object = 7
ITEM_Uninitialized = 8

VERIFICATION_TYPE_INFO = {
    ITEM_Top: ["Top_variable_info", '>B', namedtuple("Top_variable_info", "tag")],
    ITEM_Integer: ["Integer_variable_info", '>B', namedtuple("Integer_variable_info", "tag")],
    ITEM_Float: ["Float_variable_info", '>B', namedtuple("Float_variable_info", "tag")],
    ITEM_Long: ["Long_variable_info", '>B', namedtuple("Long_variable_info", "tag")],
    ITEM_Double: ["Double_variable_info", '>B', namedtuple("Double_variable_info", "tag")],
    ITEM_Null: ["Null_variable_info", '>B', namedtuple("Null_variable_info", "tag")],
    ITEM_UninitializedThis: ["UninitializedThis_variable_info", '>B',
                             namedtuple("UninitializedThis_variable_info", "tag")],
    ITEM_Object: ["Object_variable_info", '>BH', namedtuple("Object_variable_info", "tag cpool_index"),
                  [("cpool_index", "get_class")]],
    ITEM_Uninitialized: ["Uninitialized_variable_info", '>BH', namedtuple("Uninitialized_variable_info", "tag offset")],
}


class FieldInfo:
    """An object which represents a Field"""

    def __init__(self, class_manager, buff):
        self.__raw_buff = buff.read(calcsize(FIELD_INFO[0]))
        self.format = SVs(FIELD_INFO[0], FIELD_INFO[1], self.__raw_buff)

        self.__CM = class_manager
        self.__attributes = []

        for i in range(0, self.format.get_value().attributes_count):
            ai = AttributeInfo(self.__CM, buff)
            self.__attributes.append(ai)

    def get_raw(self):
        return self.__raw_buff + ''.join(x.get_raw() for x in self.__attributes)

    def get_length(self):
        val = 0
        for i in self.__attributes:
            val += i.length
        return val + calcsize(FIELD_INFO[0])

    def get_access(self):
        try:
            return ACC_FIELD_FLAGS[self.format.get_value().access_flags][0]
        except KeyError:
            ok = True
            access = ""
            for i in ACC_FIELD_FLAGS:
                if (i & self.format.get_value().access_flags) == i:
                    access += ACC_FIELD_FLAGS[i][0] + " "
                    ok = False

            if ok == False:
                return access[:-1]

            return "ACC_PRIVATE"

    def set_access(self, value):
        self.format.set_value({"access_flags": value})

    def get_class_name(self):
        return self.__CM.get_this_class_name()

    def get_name(self):
        return self.__CM.get_string(self.format.get_value().name_index)

    def set_name(self, name):
        return self.__CM.set_string(self.format.get_value().name_index, name)

    def get_descriptor(self):
        return self.__CM.get_string(self.format.get_value().descriptor_index)

    def set_descriptor(self, name):
        return self.__CM.set_string(self.format.get_value().descriptor_index, name)

    def get_attributes(self):
        return self.__attributes

    def get_name_index(self):
        return self.format.get_value().name_index

    def get_descriptor_index(self):
        return self.format.get_value().descriptor_index

    def show(self):
        print self.format.get_value(), self.get_name(), self.get_descriptor()
        for i in self.__attributes:
            i.show()


class MethodInfo:
    """An object which represents a Method"""

    def __init__(self, class_manager, buff):
        self.format = SVs(METHOD_INFO[0], METHOD_INFO[1], buff.read(calcsize(METHOD_INFO[0])))

        self.__CM = class_manager
        self.__code = None
        self.__attributes = []

        for i in range(0, self.format.get_value().attributes_count):
            ai = AttributeInfo(self.__CM, buff)
            self.__attributes.append(ai)

            if ai.get_name() == "Code":
                self.__code = ai

    def get_raw(self):
        return self.format.get_value_buff() + ''.join(x.get_raw() for x in self.__attributes)

    def get_length(self):
        val = 0
        for i in self.__attributes:
            val += i.length

        return val + calcsize(METHOD_INFO[0])

    def get_attributes(self):
        return self.__attributes

    def get_access(self):
        return ACC_METHOD_FLAGS[self.format.get_value().access_flags][0]

    def set_access(self, value):
        self.format.set_value({"access_flags": value})

    def get_name(self):
        return self.__CM.get_string(self.format.get_value().name_index)

    def set_name(self, name):
        return self.__CM.set_string(self.format.get_value().name_index, name)

    def get_descriptor(self):
        return self.__CM.get_string(self.format.get_value().descriptor_index)

    def set_descriptor(self, name):
        return self.__CM.set_string(self.format.get_value().name_descriptor, name)

    def get_name_index(self):
        return self.format.get_value().name_index

    def get_descriptor_index(self):
        return self.format.get_value().descriptor_index

    def get_local_variables(self):
        return self.get_code().get_local_variables()

    def get_code(self):
        if self.__code == None:
            return None
        return self.__code.get_item()

    def set_name_index(self, name_index):
        self.format.set_value({"name_index": name_index})

    def set_descriptor_index(self, descriptor_index):
        self.format.set_value({"descriptor_index": descriptor_index})

    def get_class_name(self):
        return self.__CM.get_this_class_name()

    def set_cm(self, cm):
        self.__CM = cm
        for i in self.__attributes:
            i.set_cm(cm)

    def with_descriptor(self, descriptor):
        return descriptor == self.__CM.get_string(self.format.get_value().descriptor_index)

    def _patch_bytecodes(self):
        return self.get_code()._patch_bytecodes()

    def show(self):
        print "*" * 80
        print self.format.get_value(), self.get_class_name(), self.get_name(), self.get_descriptor()
        for i in self.__attributes:
            i.show()
        print "*" * 80

    def pretty_show(self, vm_a):
        print "*" * 80
        print self.format.get_value(), self.get_class_name(), self.get_name(), self.get_descriptor()
        for i in self.__attributes:
            i.pretty_show(vm_a.hmethods[self])
        print "*" * 80


class CreateString:
    """Create a specific String constant by given the name index"""

    def __init__(self, class_manager, bytes):
        self.__string_index = class_manager.add_string(bytes)

    def get_raw(self):
        tag_value = INVERT_CONSTANT_INFO["CONSTANT_String"]
        buff = pack(CONSTANT_INFO[tag_value][1], tag_value, self.__string_index)

        return buff


class CreateInteger:
    """Create a specific Integer constant by given the name index"""

    def __init__(self, byte):
        self.__byte = byte

    def get_raw(self):
        tag_value = INVERT_CONSTANT_INFO["CONSTANT_Integer"]
        buff = pack(CONSTANT_INFO[tag_value][1], tag_value, self.__byte)

        return buff


class CreateClass:
    """Create a specific Class constant by given the name index"""

    def __init__(self, class_manager, name_index):
        self.__CM = class_manager

        self.__name_index = name_index

    def get_raw(self):
        tag_value = INVERT_CONSTANT_INFO["CONSTANT_Class"]
        buff = pack(CONSTANT_INFO[tag_value][1], tag_value, self.__name_index)

        return buff


class CreateNameAndType:
    """Create a specific NameAndType constant by given the name and the descriptor index"""

    def __init__(self, class_manager, name_index, descriptor_index):
        self.__CM = class_manager

        self.__name_index = name_index
        self.__descriptor_index = descriptor_index

    def get_raw(self):
        tag_value = INVERT_CONSTANT_INFO["CONSTANT_NameAndType"]
        buff = pack(CONSTANT_INFO[tag_value][1], tag_value, self.__name_index, self.__descriptor_index)

        return buff


class CreateFieldRef:
    """Create a specific FieldRef constant by given the class and the NameAndType index"""

    def __init__(self, class_manager, class_index, name_and_type_index):
        self.__CM = class_manager

        self.__class_index = class_index
        self.__name_and_type_index = name_and_type_index

    def get_raw(self):
        tag_value = INVERT_CONSTANT_INFO["CONSTANT_Fieldref"]
        buff = pack(CONSTANT_INFO[tag_value][1], tag_value, self.__class_index, self.__name_and_type_index)

        return buff


class CreateMethodRef:
    """Create a specific MethodRef constant by given the class and the NameAndType index"""

    def __init__(self, class_manager, class_index, name_and_type_index):
        self.__CM = class_manager

        self.__class_index = class_index
        self.__name_and_type_index = name_and_type_index

    def get_raw(self):
        tag_value = INVERT_CONSTANT_INFO["CONSTANT_Methodref"]
        buff = pack(CONSTANT_INFO[tag_value][1], tag_value, self.__class_index, self.__name_and_type_index)

        return buff


class CreateCodeAttributeInfo:
    """Create a specific CodeAttributeInfo by given bytecodes (into an human readable format)"""

    def __init__(self, class_manager, codes):
        self.__CM = class_manager

        #ATTRIBUTE_INFO  =                    [ '>HL', namedtuple("AttributeInfo", "attribute_name_index attribute_length") ]
        self.__attribute_name_index = self.__CM.get_string_index("Code")
        self.__attribute_length = 0
        ########

        # CODE_LOW_STRUCT            =         [ '>HHL', namedtuple( "LOW", "max_stack max_locals code_length" ) ]
        self.__max_stack = 1
        self.__max_locals = 2
        self.__code_length = 0
        ########

        # CODE
        raw_buff = ""

        for i in codes:
            op_name = i[0]
            op_value = INVERT_JAVA_OPCODES[op_name]
            raw_buff += pack('>B', op_value)

            if len(JAVA_OPCODES[op_value]) > 1:
                r_function, v_function, r_buff, r_format, f_function = EXTRACT_INFORMATION_SIMPLE(op_value)
                raw_buff += pack(r_format, *v_function(*i[1:]))

        self.__code = JavaCode(self.__CM, raw_buff)
        self.__code_length = len(raw_buff)
        ########

        # EXCEPTION
        # u2 exception_table_length;
        self.__exception_table_length = 0

        # {                u2 start_pc;
        #                  u2 end_pc;
        #                  u2  handler_pc;
        #                  u2  catch_type;
        # }        exception_table[exception_table_length];
        self.__exception_table = []
        ########

        # ATTRIBUTES
        # u2 attributes_count;
        self.__attributes_count = 0

        # attribute_info attributes[attributes_count];
        self.__attributes = []
        ########

        # FIXME : remove calcsize
        self.__attribute_length = calcsize(ATTRIBUTE_INFO[0]) + \
                                  calcsize(CODE_LOW_STRUCT[0]) + \
                                  self.__code_length + \
                                  calcsize('>H') + \
                                  calcsize('>H')

    def get_raw(self):
        return pack(ATTRIBUTE_INFO[0], self.__attribute_name_index, self.__attribute_length) + \
               pack(CODE_LOW_STRUCT[0], self.__max_stack, self.__max_locals, self.__code_length) + \
               self.__code.get_raw() + \
               pack('>H', self.__exception_table_length) + \
               ''.join(i.get_raw() for i in self.__exception_table) + \
               pack('>H', self.__attributes_count) + \
               ''.join(i.get_raw() for i in self.__attributes)

# FIELD_INFO                  =         [ '>HHHH',        namedtuple("FieldInfo", "access_flags name_index descriptor_index attributes_count") ]
class CreateFieldInfo:
    """Create a specific FieldInfo by given the name, the prototype of the "new" field"""

    def __init__(self, class_manager, name, proto):
        self.__CM = class_manager

        access_flags_value = proto[0]
        type_value = proto[1]

        self.__access_flags = INVERT_ACC_FIELD_FLAGS[access_flags_value]
        self.__name_index = self.__CM.get_string_index(name)
        if self.__name_index == -1:
            self.__name_index = self.__CM.add_string(name)
        else:
            bytecode.Exit("field %s is already present ...." % name)

        self.__descriptor_index = self.__CM.add_string(type_value)

        self.__attributes = []

    def get_raw(self):
        buff = pack(FIELD_INFO[0], self.__access_flags, self.__name_index, self.__descriptor_index,
                    len(self.__attributes))

        for i in self.__attributes:
            buff += i.get_raw()

        return buff

# METHOD_INFO      =                    [ '>HHHH', namedtuple("MethodInfo", "access_flags name_index descriptor_index attributes_count") ]
class CreateMethodInfo:
    """Create a specific MethodInfo by given the name, the prototype and the code (into an human readable format) of the "new" method"""

    def __init__(self, class_manager, name, proto, codes):
        self.__CM = class_manager

        access_flags_value = proto[0]
        return_value = proto[1]
        arguments_value = proto[2]

        self.__access_flags = INVERT_ACC_METHOD_FLAGS[access_flags_value]

        self.__name_index = self.__CM.get_string_index(name)
        if self.__name_index == -1:
            self.__name_index = self.__CM.add_string(name)

        proto_final = "(" + arguments_value + ")" + return_value
        self.__descriptor_index = self.__CM.add_string(proto_final)

        self.__attributes = []

        self.__attributes.append(CreateCodeAttributeInfo(self.__CM, codes))

    def get_raw(self):
        buff = pack(METHOD_INFO[0], self.__access_flags, self.__name_index, self.__descriptor_index,
                    len(self.__attributes))

        for i in self.__attributes:
            buff += i.get_raw()

        return buff


class JBC:
    """JBC manages each bytecode with the value, name, raw buffer and special functions"""
    # special --> ( r_function, v_function, r_buff, r_format, f_function )
    def __init__(self, class_manager, op_name, raw_buff, special=None):
        self.__CM = class_manager
        self.__op_name = op_name
        self.__raw_buff = raw_buff

        self.__special = special
        self.__special_value = None

        self._load()

    def _load(self):
        if self.__special != None:
            ntuple = namedtuple(self.__op_name, self.__special[2])
            x = ntuple._make(unpack(self.__special[3], self.__raw_buff[1:]))

            if self.__special[4] == None:
                self.__special_value = self.__special[0](x)
            else:
                self.__special_value = getattr(self.__CM, self.__special[4])(self.__special[0](x))

    def reload(self, raw_buff):
        """Reload the bytecode with a new raw buffer"""
        self.__raw_buff = raw_buff
        self._load()

    def set_cm(self, cm):
        self.__CM = cm

    def get_length(self):
        """Return the length of the bytecode"""
        return len(self.__raw_buff)

    def get_raw(self):
        """Return the current raw buffer of the bytecode"""
        return self.__raw_buff

    def get_name(self):
        """Return the name of the bytecode"""
        return self.__op_name

    def get_operands(self):
        """Return the operands of the bytecode"""
        if isinstance(self.__special_value, list):
            if len(self.__special_value) == 1:
                return self.__special_value[0]
        return self.__special_value

    def get_formatted_operands(self):
        return []

    def adjust_r(self, pos, pos_modif, len_modif):
        """Adjust the bytecode (if necessary (in this cas the bytecode is a branch bytecode)) when a bytecode has been removed"""
        #        print self.__op_name, pos, pos_modif, len_modif, self.__special_value, type(pos), type(pos_modif), type(len_modif), type(self.__special_value)

        if pos > pos_modif:
            if (self.__special_value + pos) < (pos_modif):
            #                print "MODIF +", self.__special_value, len_modif,
                self.__special_value += len_modif
                #                print self.__special_value
                self.__raw_buff = pack('>B', INVERT_JAVA_OPCODES[self.__op_name]) + pack(self.__special[3],
                                                                                         *self.__special[1](
                                                                                             self.__special_value))

        elif pos < pos_modif:
            if (self.__special_value + pos) > (pos_modif):
            #                print "MODIF -", self.__special_value, len_modif,
                self.__special_value -= len_modif
                #                print self.__special_value
                self.__raw_buff = pack('>B', INVERT_JAVA_OPCODES[self.__op_name]) + pack(self.__special[3],
                                                                                         *self.__special[1](
                                                                                             self.__special_value))

    def adjust_i(self, pos, pos_modif, len_modif):
        """Adjust the bytecode (if necessary (in this cas the bytecode is a branch bytecode)) when a bytecode has been inserted"""
        #print self.__op_name, pos, pos_modif, len_modif, self.__special_value, type(pos), type(pos_modif), type(len_modif), type(self.__special_value)

        if pos > pos_modif:
            if (self.__special_value + pos) < (pos_modif):
            #                print "MODIF +", self.__special_value, len_modif,
                self.__special_value -= len_modif
                #                print self.__special_value
                self.__raw_buff = pack('>B', INVERT_JAVA_OPCODES[self.__op_name]) + pack(self.__special[3],
                                                                                         *self.__special[1](
                                                                                             self.__special_value))

        elif pos < pos_modif:
            if (self.__special_value + pos) > (pos_modif):
            #                print "MODIF -", self.__special_value, len_modif,
                self.__special_value += len_modif
                #                print self.__special_value
                self.__raw_buff = pack('>B', INVERT_JAVA_OPCODES[self.__op_name]) + pack(self.__special[3],
                                                                                         *self.__special[1](
                                                                                             self.__special_value))

    def show_buff(self, pos):
        buff = ""
        if self.__special_value == None:
            buff += self.__op_name
        else:
            if self.__op_name in BRANCH_JVM_OPCODES:
                buff += "%s %s %s" % (self.__op_name, self.__special_value, self.__special_value + pos)
            else:
                buff += "%s %s" % (self.__op_name, self.__special_value)

        return buff

    def show(self, pos):
        """Show the bytecode at a specific position

            pos - the position into the bytecodes (integer)
        """
        print self.show_buff(pos),


class JavaCode:
    """JavaCode manages a list of bytecode to a specific method, by decoding a raw buffer and transform each bytecode into a JBC object"""

    def __init__(self, class_manager, buff):
        self.__CM = class_manager

        self.__raw_buff = buff
        self.__bytecodes = []
        self.__maps = []
        self.__branches = []

        i = 0
        while i < len(self.__raw_buff):
            op_value = unpack('>B', self.__raw_buff[i])[0]
            if op_value in JAVA_OPCODES:
                if len(JAVA_OPCODES[op_value]) >= 2:
                    # it's a fixed length opcode
                    if isinstance(JAVA_OPCODES[op_value][1], str) == True:
                        r_function, v_function, r_buff, r_format, f_function = EXTRACT_INFORMATION_SIMPLE(op_value)
                    # it's a variable length opcode
                    else:
                        r_function, v_function, r_buff, r_format, f_function = EXTRACT_INFORMATION_VARIABLE(i, op_value,
                                                                                                            self.__raw_buff[
                                                                                                            i:])

                    len_format = calcsize(r_format)
                    raw_buff = self.__raw_buff[i: i + 1 + len_format]

                    jbc = JBC(class_manager, JAVA_OPCODES[op_value][0], raw_buff,
                              ( r_function, v_function, r_buff, r_format, f_function ))
                    self.__bytecodes.append(jbc)

                    i += len_format
                else:
                    self.__bytecodes.append(JBC(class_manager, JAVA_OPCODES[op_value][0], self.__raw_buff[i]))
            else:
                bytecode.Exit("op_value 0x%x is unknown" % op_value)

            i += 1

        # Create branch bytecodes list
        idx = 0
        nb = 0
        for i in self.__bytecodes:
            self.__maps.append(idx)

            if i.get_name() in BRANCH_JVM_OPCODES:
                self.__branches.append(nb)

            idx += i.get_length()
            nb += 1

    def _patch_bytecodes(self):
        methods = []
        for i in self.__bytecodes:
            if "invoke" in i.get_name():
                operands = i.get_operands()
                methods.append(operands)
                op_value = INVERT_JAVA_OPCODES[i.get_name()]
                raw_buff = pack('>B', op_value)

                r_function, v_function, r_buff, r_format, f_function = EXTRACT_INFORMATION_SIMPLE(op_value)

                new_class_index = self.__CM.create_class(operands[0])
                new_name_and_type_index = self.__CM.create_name_and_type(operands[1], operands[2])

                self.__CM.create_method_ref(new_class_index, new_name_and_type_index)

                value = getattr(self.__CM, JAVA_OPCODES[op_value][5])(*operands[0:])
                if value == -1:
                    bytecode.Exit("Unable to found method " + str(operands))

                raw_buff += pack(r_format, *v_function(value))

                i.reload(raw_buff)

            elif "anewarray" in i.get_name():
                operands = i.get_operands()
                op_value = INVERT_JAVA_OPCODES[i.get_name()]
                raw_buff = pack('>B', op_value)

                r_function, v_function, r_buff, r_format, f_function = EXTRACT_INFORMATION_SIMPLE(op_value)

                new_class_index = self.__CM.create_class(operands)

                raw_buff += pack(r_format, *v_function(new_class_index))

                i.reload(raw_buff)

            elif "getstatic" == i.get_name():
                operands = i.get_operands()
                op_value = INVERT_JAVA_OPCODES[i.get_name()]
                raw_buff = pack('>B', op_value)

                r_function, v_function, r_buff, r_format, f_function = EXTRACT_INFORMATION_SIMPLE(op_value)

                new_class_index = self.__CM.create_class(operands[0])
                new_name_and_type_index = self.__CM.create_name_and_type(operands[1], operands[2])

                self.__CM.create_field_ref(new_class_index, new_name_and_type_index)

                value = getattr(self.__CM, JAVA_OPCODES[op_value][5])(*operands[1:])
                if value == -1:
                    bytecode.Exit("Unable to found method " + str(operands))

                raw_buff += pack(r_format, *v_function(value))

                i.reload(raw_buff)

            elif "ldc" == i.get_name():
                operands = i.get_operands()
                op_value = INVERT_JAVA_OPCODES[i.get_name()]
                raw_buff = pack('>B', op_value)

                r_function, v_function, r_buff, r_format, f_function = EXTRACT_INFORMATION_SIMPLE(op_value)

                if operands[0] != "CONSTANT_Integer" and operands[0] != "CONSTANT_String":
                    bytecode.Exit("....")

                if operands[0] == "CONSTANT_Integer":
                    new_int_index = self.__CM.create_integer(operands[1])
                    raw_buff += pack(r_format, *v_function(new_int_index))

                elif operands[0] == "CONSTANT_String":
                    new_string_index = self.__CM.create_string(operands[1])

                    raw_buff += pack(r_format, *v_function(new_string_index))

                i.reload(raw_buff)

            elif "new" == i.get_name():
                operands = i.get_operands()
                op_value = INVERT_JAVA_OPCODES[i.get_name()]
                raw_buff = pack('>B', op_value)

                r_function, v_function, r_buff, r_format, f_function = EXTRACT_INFORMATION_SIMPLE(op_value)

                new_class_index = self.__CM.create_class(operands)

                raw_buff += pack(r_format, *v_function(new_class_index))

                i.reload(raw_buff)

        return methods

    def get(self):
        """
            Return all bytecodes

            @rtype : L{list}
        """
        return self.__bytecodes

    def get_raw(self):
        return ''.join(x.get_raw() for x in self.__bytecodes)

    def show(self):
        """
            Display the code like a disassembler
        """
        nb = 0
        for i in self.__bytecodes:
            print nb, self.__maps[nb],
            i.show(self.__maps[nb])
            print
            nb += 1

    def pretty_show(self, m_a):
        """
            Display the code like a disassembler but with instructions' links
        """
        bytecode.PrettyShow(m_a.basic_blocks.gets())
        bytecode.PrettyShowEx(m_a.exceptions.gets())

    def get_relative_idx(self, idx):
        """
            Return the relative idx by given an offset in the code

            @param idx : an offset in the code

            @rtype : the relative index in the code, it's the position in the list of a bytecode
        """
        n = 0
        x = 0
        for i in self.__bytecodes:
            #print n, idx
            if n == idx:
                return x
            n += i.get_length()
            x += 1
        return -1

    def get_at(self, idx):
        """
            Return a specific bytecode at an index

            @param : the index of a bytecode

            @rtype : L{JBC}
        """
        return self.__bytecodes[idx]

    def remove_at(self, idx):
        """
            Remove bytecode at a specific index

            @param idx : the index to remove the bytecode

            @rtype : the length of the removed bytecode
        """
        val = self.__bytecodes[idx]
        val_m = self.__maps[idx]

        # Remove the index if it's in our branch list
        if idx in self.__branches:
            self.__branches.remove(idx)

        # Adjust each branch
        for i in self.__branches:
            self.__bytecodes[i].adjust_r(self.__maps[i], val_m, val.get_length())

        # Remove it !
        self.__maps.pop(idx)
        self.__bytecodes.pop(idx)

        # Adjust branch and map list
        self._adjust_maps(val_m, val.get_length() * -1)
        self._adjust_branches(idx, -1)

        return val.get_length()

    def _adjust_maps(self, val, size):
        nb = 0
        for i in self.__maps:
            if i > val:
                self.__maps[nb] = i + size
            nb = nb + 1

    def _adjust_maps_i(self, val, size):
        nb = 0
        x = 0
        for i in self.__maps:
            if i == val:
                x += 1

            if x == 2:
                self.__maps[nb] = i + size

            if i > val:
                self.__maps[nb] = i + size
            nb = nb + 1

    def _adjust_branches(self, val, size):
        nb = 0
        for i in self.__branches:
            if i > val:
                self.__branches[nb] = i + size
            nb += 1

    def insert_at(self, idx, byte_code):
        """
            Insert bytecode at a specific index

            @param idx : the index to insert the bytecode
            @param bytecode : a list which represent the bytecode

            @rtype : the length of the inserted bytecode
        """
        # Get the op_value and add it to the raw_buff
        op_name = byte_code[0]
        op_value = INVERT_JAVA_OPCODES[op_name]
        raw_buff = pack('>B', op_value)

        new_jbc = None

        # If it's an op_value with args, we must handle that !
        if len(JAVA_OPCODES[op_value]) > 1:

            # Find information about the op_value
            r_function, v_function, r_buff, r_format, f_function = EXTRACT_INFORMATION_SIMPLE(op_value)

            # Special values for this op_value (advanced bytecode)
            if len(JAVA_OPCODES[op_value]) == 6:

                value = getattr(self.__CM, JAVA_OPCODES[op_value][5])(*byte_code[1:])
                if value == -1:
                    bytecode.Exit("Unable to found " + str(byte_code[1:]))

                raw_buff += pack(r_format, *v_function(value))
            else:
                raw_buff += pack(r_format, *v_function(*byte_code[1:]))

            new_jbc = JBC(self.__CM, op_name, raw_buff, ( r_function, v_function, r_buff, r_format, f_function ))
        else:
            new_jbc = JBC(self.__CM, op_name, raw_buff)

        # Adjust each branch with the new insertion
        val_m = self.__maps[idx]
        for i in self.__branches:
            self.__bytecodes[i].adjust_i(self.__maps[i], val_m, new_jbc.get_length())

        # Insert the new bytecode at the correct index
        # Adjust maps + branches
        self.__bytecodes.insert(idx, new_jbc)
        self.__maps.insert(idx, val_m)
        self._adjust_maps_i(val_m, new_jbc.get_length())

        self._adjust_branches(idx, 1)

        # Add it to the branches if it's a correct op_value
        if new_jbc.get_name() in BRANCH_JVM_OPCODES:
            self.__branches.append(idx)

        # FIXME
        # modify the exception table
        # modify tableswitch and lookupswitch instructions

        # return the length of the raw_buff
        return len(raw_buff)

    def remplace_at(self, idx, bytecode):
        """
            Remplace bytecode at a specific index by another bytecode (remplace = remove + insert)

            @param idx : the index to insert the bytecode
            @param bytecode : a list which represent the bytecode

            @rtype : the length of the inserted bytecode
        """
        self.remove_at(idx) * (-1)
        size = self.insert_at(idx, bytecode)

        return size

    def set_cm(self, cm):
        self.__CM = cm
        for i in self.__bytecodes:
            i.set_cm(cm)


class BasicAttribute(object):
    def __init__(self):
        self.__attributes = []

    def get_attributes(self):
        return self.__attributes

    def set_cm(self, cm):
        self.__CM = cm


class CodeAttribute(BasicAttribute):
    def __init__(self, class_manager, buff):
        self.__CM = class_manager

        super(CodeAttribute, self).__init__()
        # u2 attribute_name_index;
        # u4 attribute_length;

        # u2 max_stack;
        # u2 max_locals;
        # u4 code_length;
        # u1 code[code_length];
        self.low_struct = SVs(CODE_LOW_STRUCT[0], CODE_LOW_STRUCT[1], buff.read(calcsize(CODE_LOW_STRUCT[0])))

        self.__code = JavaCode(class_manager, buff.read(self.low_struct.get_value().code_length))

        # u2 exception_table_length;
        self.exception_table_length = SV('>H', buff.read(2))

        # {                u2 start_pc;
        #                  u2 end_pc;
        #                  u2  handler_pc;
        #                  u2  catch_type;
        # }        exception_table[exception_table_length];
        self.__exception_table = []
        for i in range(0, self.exception_table_length.get_value()):
            et = SVs(EXCEPTION_TABLE[0], EXCEPTION_TABLE[1], buff.read(calcsize(EXCEPTION_TABLE[0])))
            self.__exception_table.append(et)

        # u2 attributes_count;
        self.attributes_count = SV('>H', buff.read(2))

        # attribute_info attributes[attributes_count];
        self.__attributes = []
        for i in range(0, self.attributes_count.get_value()):
            ai = AttributeInfo(self.__CM, buff)
            self.__attributes.append(ai)

    def get_attributes(self):
        return self.__attributes

    def get_exceptions(self):
        return self.__exception_table

    def get_raw(self):
        return self.low_struct.get_value_buff() + \
               self.__code.get_raw() + \
               self.exception_table_length.get_value_buff() + \
               ''.join(x.get_value_buff() for x in self.__exception_table) + \
               self.attributes_count.get_value_buff() + \
               ''.join(x.get_raw() for x in self.__attributes)

    def get_length(self):
        return self.low_struct.get_value().code_length


    def get_max_stack(self):
        return self.low_struct.get_value().max_stack

    def get_max_locals(self):
        return self.low_struct.get_value().max_locals

    def get_local_variables(self):
        for i in self.__attributes:
            if i.get_name() == "StackMapTable":
                return i.get_item().get_local_variables()
        return []

    def get_bc(self):
        return self.__code

    # FIXME : show* --> add exceptions
    def show_info(self):
        print "!" * 70
        print self.low_struct.get_value()
        bytecode._Print("ATTRIBUTES_COUNT", self.attributes_count.get_value())
        for i in self.__attributes:
            i.show()
        print "!" * 70

    def _begin_show(self):
        print "!" * 70
        print self.low_struct.get_value()

    def _end_show(self):
        bytecode._Print("ATTRIBUTES_COUNT", self.attributes_count.get_value())
        for i in self.__attributes:
            i.show()
        print "!" * 70

    def show(self):
        self._begin_show()
        self.__code.show()
        self._end_show()

    def pretty_show(self, m_a):
        self._begin_show()
        self.__code.pretty_show(m_a)
        self._end_show()

    def _patch_bytecodes(self):
        return self.__code._patch_bytecodes()

    def remplace_at(self, idx, bytecode):
        size = self.__code.remplace_at(idx, bytecode)

        # Adjust the length of our bytecode
        self.low_struct.set_value({"code_length": self.low_struct.get_value().code_length + size})

    def remove_at(self, idx):
        size = self.__code.remove_at(idx)
        # Adjust the length of our bytecode
        self.low_struct.set_value({"code_length": self.low_struct.get_value().code_length - size})

    def removes_at(self, l_idx):
        i = 0
        while i < len(l_idx):
            self.remove_at(l_idx[i])

            j = i + 1
            while j < len(l_idx):
                if l_idx[j] > l_idx[i]:
                    l_idx[j] -= 1

                j += 1

            i += 1

    def inserts_at(self, idx, l_bc):
    #        self.low_struct.set_value( { "max_stack" : self.low_struct.get_value().max_stack + 2 } )
    #        print self.low_struct.get_value()
        total_size = 0
        for i in l_bc:
            size = self.insert_at(idx, i)
            idx += 1
            total_size += size
        return total_size

    def insert_at(self, idx, bytecode):
        size = self.__code.insert_at(idx, bytecode)
        # Adjust the length of our bytecode
        self.low_struct.set_value({"code_length": self.low_struct.get_value().code_length + size})

        return size

    def get_relative_idx(self, idx):
        return self.__code.get_relative_idx(idx)

    def get_at(self, idx):
        return self.__code.get_at(idx)

    def gets_at(self, l_idx):
        return [self.__code.get_at(i) for i in l_idx]

    def set_cm(self, cm):
        self.__CM = cm
        for i in self.__attributes:
            i.set_cm(cm)
        self.__code.set_cm(cm)

    def _fix_attributes(self, new_cm):
        for i in self.__attributes:
            i._fix_attributes(new_cm)


class SourceFileAttribute(BasicAttribute):
    def __init__(self, cm, buff):
        super(SourceFileAttribute, self).__init__()
        # u2 attribute_name_index;
        # u4 attribute_length;

        # u2 sourcefile_index;
        self.sourcefile_index = SV('>H', buff.read(2))

    def get_raw(self):
        return self.sourcefile_index.get_value_buff()

    def show(self):
        print self.sourcefile_index


class LineNumberTableAttribute(BasicAttribute):
    def __init__(self, cm, buff):
        super(LineNumberTableAttribute, self).__init__()
        # u2 attribute_name_index;
        # u4 attribute_length;

        # u2 line_number_table_length;
        # {  u2 start_pc;
        #     u2 line_number;
        # } line_number_table[line_number_table_length];

        self.line_number_table_length = SV('>H', buff.read(2))

        self.__line_number_table = []
        for i in range(0, self.line_number_table_length.get_value()):
            lnt = SVs(LINE_NUMBER_TABLE[0], LINE_NUMBER_TABLE[1], buff.read(4))
            self.__line_number_table.append(lnt)

    def get_raw(self):
        return self.line_number_table_length.get_value_buff() + \
               ''.join(x.get_value_buff() for x in self.__line_number_table)

    def get_line_number_table(self):
        return self.__line_number_table

    def show(self):
        bytecode._Print("LINE_NUMBER_TABLE_LENGTH", self.line_number_table_length.get_value())
        for x in self.__line_number_table:
            print "\t", x.get_value()

    def _fix_attributes(self, new_cm):
        pass


class LocalVariableTableAttribute(BasicAttribute):
    def __init__(self, cm, buff):
        super(LocalVariableTableAttribute, self).__init__()
        # u2 attribute_name_index;
        # u4 attribute_length;

        # u2 local_variable_table_length;
        # {  u2 start_pc;
        #     u2 length;
        #     u2 name_index;
        #     u2 descriptor_index;
        #     u2 index;
        # } local_variable_table[local_variable_table_length];
        self.local_variable_table_length = SV('>H', buff.read(2))

        self.local_variable_table = []
        for i in range(0, self.local_variable_table_length.get_value()):
            lvt = SVs(LOCAL_VARIABLE_TABLE[0], LOCAL_VARIABLE_TABLE[1], buff.read(calcsize(LOCAL_VARIABLE_TABLE[0])))
            self.local_variable_table.append(lvt)

    def get_raw(self):
        return self.local_variable_table_length.get_value_buff() + \
               ''.join(x.get_value_buff() for x in self.local_variable_table)

    def show(self):
        print "LocalVariableTable", self.local_variable_table_length.get_value()
        for x in self.local_variable_table:
            print x.get_value()


class LocalVariableTypeTableAttribute(BasicAttribute):
    def __init__(self, cm, buff):
        super(LocalVariableTypeTableAttribute, self).__init__()
        # u2 attribute_name_index;
        # u4 attribute_length;

        # u2 local_variable_type_table_length;
        # { u2 start_pc;
        #    u2 length;
        #    u2 name_index;
        #    u2 signature_index;
        #    u2 index;
        # } local_variable_type_table[local_variable_type_table_length];
        self.local_variable_type_table_length = SV('>H', buff.read(2))

        self.local_variable_type_table = []
        for i in range(0, self.local_variable_type_table_length.get_value()):
            lvtt = SVs(LOCAL_VARIABLE_TYPE_TABLE[0], LOCAL_VARIABLE_TYPE_TABLE[1],
                       buff.read(calcsize(LOCAL_VARIABLE_TYPE_TABLE[0])))
            self.local_variable_type_table.append(lvtt)

    def get_raw(self):
        return self.local_variable_type_table_length.get_value_buff() + \
               ''.join(x.get_value_buff() for x in self.local_variable_type_table)

    def show(self):
        print "LocalVariableTypeTable", self.local_variable_type_table_length.get_value()
        for x in self.local_variable_type_table:
            print x.get_value()


class SourceDebugExtensionAttribute(BasicAttribute):
    def __init__(self, cm, buff):
        super(SourceDebugExtensionAttribute, self).__init__()
        # u2 attribute_name_index;
        # u4 attribute_length;
        # u1 debug_extension[attribute_length];

        self.debug_extension = buff.read(self.attribute_length)

    def get_raw(self):
        return self.debug_extension

    def show(self):
        print "SourceDebugExtension", self.debug_extension.get_value()


class DeprecatedAttribute(BasicAttribute):
    def __init__(self, cm, buff):
        super(DeprecatedAttribute, self).__init__()
        # u2 attribute_name_index;
        # u4 attribute_length;

    def get_raw(self):
        return ''

    def show(self):
        print "Deprecated"


class SyntheticAttribute(BasicAttribute):
    def __init__(self, cm, buff):
        super(SyntheticAttribute, self).__init__()
        # u2 attribute_name_index;
        # u4 attribute_length;

    def get_raw(self):
        return ''

    def show(self):
        print "Synthetic"


class SignatureAttribute(BasicAttribute):
    def __init__(self, cm, buff):
        super(SignatureAttribute, self).__init__()
        # u2 attribute_name_index;
        # u4 attribute_length;

        # u2 signature_index;
        self.signature_index = SV('>H', buff.read(2))

    def get_raw(self):
        return self.signature_index.get_value_buff()

    def show(self):
        print "Signature", self.signature_index.get_value()


class RuntimeVisibleAnnotationsAttribute(BasicAttribute):
    def __init__(self, cm, buff):
        super(RuntimeVisibleAnnotationsAttribute, self).__init__()
        # u2 attribute_name_index;
        # u4 attribute_length;

        # u2 num_annotations;
        # annotation annotations[num_annotations];
        self.num_annotations = SV('>H', buff.read(2))

        self.annotations = []
        for i in range(0, self.num_annotations.get_value()):
            self.annotations.append(Annotation(cm, buff))

    def get_raw(self):
        return self.num_annotations.get_value_buff() + \
               ''.join(x.get_raw() for x in self.annotations)

    def show(self):
        print "RuntimeVisibleAnnotations", self.num_annotations.get_value()
        for i in self.annotations:
            i.show()


class RuntimeInvisibleAnnotationsAttribute(RuntimeVisibleAnnotationsAttribute):
    def show(self):
        print "RuntimeInvisibleAnnotations", self.num_annotations.get_value()
        for i in self.annotations:
            i.show()


class RuntimeVisibleParameterAnnotationsAttribute(BasicAttribute):
    def __init__(self, cm, buff):
        super(RuntimeVisibleParameterAnnotationsAttribute, self).__init__()
        # u2 attribute_name_index;
        # u4 attribute_length;

        # u1 num_parameters;
        #{
        #         u2 num_annotations;
        #         annotation annotations[num_annotations];
        #} parameter_annotations[num_parameters];

        self.num_parameters = SV('>H', buff.read(2))
        self.parameter_annotations = []
        for i in range(0, self.num_parameters.get_value()):
            self.parameter_annotations.append(ParameterAnnotation(cm, buff))

    def get_raw(self):
        return self.num_parameters.get_value_buff() + \
               ''.join(x.get_raw() for x in self.parameter_annotations)

    def show(self):
        print "RuntimeVisibleParameterAnnotations", self.num_parameters.get_value()
        for i in self.parameter_annotations:
            i.show()


class RuntimeInvisibleParameterAnnotationsAttribute(RuntimeVisibleParameterAnnotationsAttribute):
    def show(self):
        print "RuntimeVisibleParameterAnnotations", self.num_annotations.get_value()
        for i in self.parameter_annotations:
            i.show()


class ParameterAnnotation:
    def __init__(self, cm, buff):
        # u2 num_annotations;
        # annotation annotations[num_annotations];
        self.num_annotations = SV('>H', buff.read(2))
        self.annotations = []

        for i in range(0, self.num_annotations.get_value()):
            self.annotations = Annotation(cm, buff)


    def get_raw(self):
        return self.num_annotations.get_value_buff() + \
               ''.join(x.get_raw() for x in self.annotations)

    def show(self):
        print "ParameterAnnotation", self.num_annotations.get_value()
        for i in self.annotations:
            i.show()


class AnnotationDefaultAttribute(BasicAttribute):
    def __init__(self, cm, buff):
        super(AnnotationDefaultAttribute, self).__init__()
        # u2 attribute_name_index;
        # u4 attribute_length;

        # element_value default_value;

        self.default_value = ElementValue(cm, buff)

    def get_raw(self):
        return self.default_value.get_raw()

    def show(self):
        print "AnnotationDefault"
        self.default_value.show()


class Annotation:
    def __init__(self, cm, buff):
        # u2 type_index;
        # u2 num_element_value_pairs;
        # {     u2 element_name_index;
        #        element_value value;
        # }     element_value_pairs[num_element_value_pairs]
        self.type_index = SV('>H', buff.read(2))
        self.num_element_value_pairs = SV('>H', buff.read(2))

        self.element_value_pairs = []

        for i in range(0, self.num_element_value_pairs.get_value()):
            self.element_value_pairs.append(ElementValuePair(cm, buff))

    def get_raw(self):
        return self.type_index.get_value_buff() + self.num_element_value_pairs.get_value_buff() + \
               ''.join(x.get_raw() for x in self.element_value_pairs)

    def show(self):
        print "Annotation", self.type_index.get_value(), self.num_element_value_pairs.get_value()
        for i in self.element_value_pairs:
            i.show()


class ElementValuePair:
    def __init__(self, cm, buff):
        # u2 element_name_index;
        # element_value value;
        self.element_name_index = SV('>H', buff.read(2))
        self.value = ElementValue(cm, buff)

    def get_raw(self):
        return self.element_name_index.get_value_buff() + \
               self.value.get_raw()

    def show(self):
        print "ElementValuePair", self.element_name_index.get_value()
        self.value.show()


ENUM_CONST_VALUE = ['>HH', namedtuple("EnumConstValue", "type_name_index const_name_index")]


class ElementValue:
    def __init__(self, cm, buff):
        # u1 tag;
        # union {
        #            u2     const_value_index;
        #            {
        #                      u2 type_name_index;
        #                      u2 const_name_index;
        #            } enum_const_value;
        #            u2     class_info_index;
        #            annotation annotation_value;
        #            {
        #                      u2     num_values;
        #                      element_value values[num_values];
        #            } array_value;
        # } value;
        self.tag = SV('>B', buff.read(1))

        tag = chr(self.tag.get_value())
        if tag == 'B' or tag == 'C' or tag == 'D' or tag == 'F' or tag == 'I' or tag == 'J' or tag == 'S' or tag == 'Z' or tag == 's':
            self.value = SV('>H', buff.read(2))
        elif tag == 'e':
            self.value = SVs(ENUM_CONST_VALUE[0], ENUM_CONST_VALUE[1], buff.read(calcsize(ENUM_CONST_VALUE[0])))
        elif tag == 'c':
            self.value = SV('>H', buff.read(2))
        elif tag == '@':
            self.value = Annotation(cm, buff)
        elif tag == '[':
            self.value = ArrayValue(cm, buff)
        else:
            bytecode.Exit("tag %c not in VERIFICATION_TYPE_INFO" % self.tag.get_value())

    def get_raw(self):
        if isinstance(self.value, SV) or isinstance(self.value, SVs):
            return self.tag.get_value_buff() + self.value.get_value_buff()

        return self.tag.get_value_buff() + self.value.get_raw()

    def show(self):
        print "ElementValue", self.tag.get_value()
        if isinstance(self.value, SV) or isinstance(self.value, SVs):
            print self.value.get_value()
        else:
            self.value.show()


class ArrayValue:
    def __init__(self, cm, buff):
        # u2     num_values;
        # element_value values[num_values];
        self.num_values = SV('>H', buff.read(2))

        self.values = []
        for i in range(0, self.num_values.get_value()):
            self.values.append(ElementValue(cm, buff))

    def get_raw(self):
        return self.num_values.get_value_buff() + \
               ''.join(x.get_raw() for x in self.values)

    def show(self):
        print "ArrayValue", self.num_values.get_value()
        for i in self.values:
            i.show()


class ExceptionsAttribute(BasicAttribute):
    def __init__(self, cm, buff):
        super(ExceptionsAttribute, self).__init__()
        # u2 attribute_name_index;
        # u4 attribute_length;

        # u2 number_of_exceptions;
        # u2 exception_index_table[number_of_exceptions];
        self.number_of_exceptions = SV('>H', buff.read(2))

        self.__exception_index_table = []
        for i in range(0, self.number_of_exceptions.get_value()):
            self.__exception_index_table.append(SV('>H', buff.read(2)))

    def get_raw(self):
        return self.number_of_exceptions.get_value_buff() + ''.join(
            x.get_value_buff() for x in self.__exception_index_table)

    def get_exception_index_table(self):
        return self.__exception_index_table

    def show(self):
        print "Exceptions", self.number_of_exceptions.get_value()
        for i in self.__exception_index_table:
            print "\t", i


class VerificationTypeInfo:
    def __init__(self, class_manager, buff):
        self.__CM = class_manager
        tag = SV('>B', buff.read_b(1)).get_value()

        if tag not in VERIFICATION_TYPE_INFO:
            bytecode.Exit("tag not in VERIFICATION_TYPE_INFO")

        format = VERIFICATION_TYPE_INFO[tag][1]
        self.format = SVs(format, VERIFICATION_TYPE_INFO[tag][2], buff.read(calcsize(format)))

    def get_raw(self):
        return self.format.get_value_buff()

    def show(self):
        general_format = self.format.get_value()
        if len(VERIFICATION_TYPE_INFO[general_format.tag]) > 3:
            print general_format,
            for (i, j) in VERIFICATION_TYPE_INFO[general_format.tag][3]:
                print getattr(self.__CM, j)(getattr(general_format, i))
        else:
            print general_format

    def _fix_attributes(self, new_cm):
        general_format = self.format.get_value()

        if len(VERIFICATION_TYPE_INFO[general_format.tag]) > 3:
            for (i, j) in VERIFICATION_TYPE_INFO[general_format.tag][3]:
                # Fix the first object which is the current class
                if getattr(self.__CM, j)(getattr(general_format, i))[0] == self.__CM.get_this_class_name():
                    self.format.set_value({"cpool_index": new_cm.get_this_class()})
                # Fix other objects
                else:
                    new_class_index = new_cm.create_class(getattr(self.__CM, j)(getattr(general_format, i))[0])
                    self.format.set_value({"cpool_index": new_class_index})

    def set_cm(self, cm):
        self.__CM = cm


class FullFrame:
    def __init__(self, class_manager, buff):
        self.__CM = class_manager
        # u1 frame_type = FULL_FRAME; /* 255 */
        # u2 offset_delta;
        # u2 number_of_locals;
        self.frame_type = SV('>B', buff.read(1))
        self.offset_delta = SV('>H', buff.read(2))
        self.number_of_locals = SV('>H', buff.read(2))

        # verification_type_info locals[number_of_locals];
        self.__locals = []
        for i in range(0, self.number_of_locals.get_value()):
            self.__locals.append(VerificationTypeInfo(self.__CM, buff))

        # u2 number_of_stack_items;
        self.number_of_stack_items = SV('>H', buff.read(2))
        # verification_type_info stack[number_of_stack_items];
        self.__stack = []
        for i in range(0, self.number_of_stack_items.get_value()):
            self.__stack.append(VerificationTypeInfo(self.__CM, buff))

    def get_locals(self):
        return self.__locals

    def get_raw(self):
        return self.frame_type.get_value_buff() + \
               self.offset_delta.get_value_buff() + \
               self.number_of_locals.get_value_buff() + \
               ''.join(x.get_raw() for x in self.__locals) + \
               self.number_of_stack_items.get_value_buff() + \
               ''.join(x.get_raw() for x in self.__stack)

    def show(self):
        print "#" * 60
        bytecode._Print("\tFULL_FRAME", self.frame_type.get_value())
        bytecode._Print("\tOFFSET_DELTA", self.offset_delta.get_value())

        bytecode._Print("\tNUMBER_OF_LOCALS", self.number_of_locals.get_value())
        for i in self.__locals:
            i.show()

        bytecode._Print("\tNUMBER_OF_STACK_ITEMS", self.number_of_stack_items.get_value())
        for i in self.__stack:
            i.show()

        print "#" * 60

    def _fix_attributes(self, new_cm):
        for i in self.__locals:
            i._fix_attributes(new_cm)

    def set_cm(self, cm):
        self.__CM = cm
        for i in self.__locals:
            i.set_cm(cm)


class ChopFrame:
    def __init__(self, buff):
        # u1 frame_type=CHOP; /* 248-250 */
        # u2 offset_delta;
        self.frame_type = SV('>B', buff.read(1))
        self.offset_delta = SV('>H', buff.read(2))

    def get_raw(self):
        return self.frame_type.get_value_buff() + self.offset_delta.get_value_buff()

    def show(self):
        print "#" * 60
        bytecode._Print("\tCHOP_FRAME", self.frame_type.get_value())
        bytecode._Print("\tOFFSET_DELTA", self.offset_delta.get_value())
        print "#" * 60

    def _fix_attributes(self, cm):
        pass

    def set_cm(self, cm):
        pass


class SameFrame:
    def __init__(self, buff):
        # u1 frame_type = SAME;/* 0-63 */
        self.frame_type = SV('>B', buff.read(1))

    def get_raw(self):
        return self.frame_type.get_value_buff()

    def show(self):
        print "#" * 60
        bytecode._Print("\tSAME_FRAME", self.frame_type.get_value())
        print "#" * 60

    def _fix_attributes(self, new_cm):
        pass

    def set_cm(self, cm):
        pass


class SameLocals1StackItemFrame:
    def __init__(self, class_manager, buff):
        self.__CM = class_manager
        # u1 frame_type = SAME_LOCALS_1_STACK_ITEM;/* 64-127 */
        # verification_type_info stack[1];
        self.frame_type = SV('>B', buff.read(1))
        self.stack = VerificationTypeInfo(self.__CM, buff)

    def show(self):
        print "#" * 60
        bytecode._Print("\tSAME_LOCALS_1_STACK_ITEM_FRAME", self.frame_type.get_value())
        self.stack.show()
        print "#" * 60

    def get_raw(self):
        return self.frame_type.get_value_buff() + self.stack.get_raw()

    def _fix_attributes(self, new_cm):
        pass

    def set_cm(self, cm):
        self.__CM = cm


class SameLocals1StackItemFrameExtended:
    def __init__(self, class_manager, buff):
        self.__CM = class_manager
        # u1 frame_type = SAME_LOCALS_1_STACK_ITEM_EXTENDED; /* 247 */
        # u2 offset_delta;
        # verification_type_info stack[1];
        self.frame_type = SV('>B', buff.read(1))
        self.offset_delta = SV('>H', buff.read(2))
        self.stack = VerificationTypeInfo(self.__CM, buff)

    def get_raw(self):
        return self.frame_type.get_value_buff() + self.offset_delta.get_value_buff() + self.stack.get_value_buff()

    def _fix_attributes(self, new_cm):
        pass

    def set_cm(self, cm):
        self.__CM = cm

    def show(self):
        print "#" * 60
        bytecode._Print("\tSAME_LOCALS_1_STACK_ITEM_FRAME_EXTENDED", self.frame_type.get_value())
        bytecode._Print("\tOFFSET_DELTA", self.offset_delta.get_value())
        self.stack.show()
        print "#" * 60


class SameFrameExtended:
    def __init__(self, buff):
        # u1 frame_type = SAME_FRAME_EXTENDED;/* 251*/
        # u2 offset_delta;
        self.frame_type = SV('>B', buff.read(1))
        self.offset_delta = SV('>H', buff.read(2))

    def get_raw(self):
        return self.frame_type.get_value_buff() + self.offset_delta.get_value_buff()

    def _fix_attributes(self, cm):
        pass

    def set_cm(self, cm):
        pass

    def show(self):
        print "#" * 60
        bytecode._Print("\tSAME_FRAME_EXTENDED", self.frame_type.get_value())
        bytecode._Print("\tOFFSET_DELTA", self.offset_delta.get_value())
        print "#" * 60


class AppendFrame:
    def __init__(self, class_manager, buff):
        self.__CM = class_manager
        # u1 frame_type = APPEND; /* 252-254 */
        # u2 offset_delta;
        self.frame_type = SV('>B', buff.read(1))
        self.offset_delta = SV('>H', buff.read(2))

        # verification_type_info locals[frame_type -251];
        self.__locals = []
        k = self.frame_type.get_value() - 251
        for i in range(0, k):
            self.__locals.append(VerificationTypeInfo(self.__CM, buff))

    def get_locals(self):
        return self.__locals

    def show(self):
        print "#" * 60
        bytecode._Print("\tAPPEND_FRAME", self.frame_type.get_value())
        bytecode._Print("\tOFFSET_DELTA", self.offset_delta.get_value())

        for i in self.__locals:
            i.show()

        print "#" * 60

    def get_raw(self):
        return self.frame_type.get_value_buff() + \
               self.offset_delta.get_value_buff() + \
               ''.join(x.get_raw() for x in self.__locals)

    def _fix_attributes(self, new_cm):
        for i in self.__locals:
            i._fix_attributes(new_cm)

    def set_cm(self, cm):
        self.__CM = cm
        for i in self.__locals:
            i.set_cm(cm)


class StackMapTableAttribute(BasicAttribute):
    def __init__(self, class_manager, buff):
        self.__CM = class_manager

        super(StackMapTableAttribute, self).__init__()
        # u2 attribute_name_index;
        # u4 attribute_length

        # u2 number_of_entries;
        self.number_of_entries = SV('>H', buff.read(2))

        # stack_map_frame entries[number_of_entries];
        self.__entries = []
        for i in range(0, self.number_of_entries.get_value()):
            frame_type = SV('>B', buff.read_b(1)).get_value()

            if frame_type >= 0 and frame_type <= 63:
                self.__entries.append(SameFrame(buff))
            elif frame_type >= 64 and frame_type <= 127:
                self.__entries.append(SameLocals1StackItemFrame(self.__CM, buff))
            elif frame_type == 247:
                self.__entries.append(SameLocals1StackItemFrameExtended(self.__CM, buff))
            elif frame_type >= 248 and frame_type <= 250:
                self.__entries.append(ChopFrame(buff))
            elif frame_type == 251:
                self.__entries.append(SameFrameExtended(buff))
            elif frame_type >= 252 and frame_type <= 254:
                self.__entries.append(AppendFrame(self.__CM, buff))
            elif frame_type == 255:
                self.__entries.append(FullFrame(self.__CM, buff))
            else:
                bytecode.Exit("Frame type %d is unknown" % frame_type)

    def get_entries(self):
        return self.__entries

    def get_local_variables(self):
        for i in self.__entries:
            if isinstance(i, FullFrame):
                return i.get_local_variables()

        return []

    def get_raw(self):
        return self.number_of_entries.get_value_buff() + \
               ''.join(x.get_raw() for x in self.__entries)

    def show(self):
        bytecode._Print("NUMBER_OF_ENTRIES", self.number_of_entries.get_value())
        for i in self.__entries:
            i.show()

    def _fix_attributes(self, new_cm):
        for i in self.__entries:
            i._fix_attributes(new_cm)

    def set_cm(self, cm):
        self.__CM = cm
        for i in self.__entries:
            i.set_cm(cm)


class InnerClassesDesc:
    def __init__(self, class_manager, buff):
        INNER_CLASSES_FORMAT = [">HHHH",
                                "inner_class_info_index outer_class_info_index inner_name_index inner_class_access_flags"]

        self.__CM = class_manager

        self.__raw_buff = buff.read(calcsize(INNER_CLASSES_FORMAT[0]))

        self.format = SVs(INNER_CLASSES_FORMAT[0], namedtuple("InnerClassesFormat", INNER_CLASSES_FORMAT[1]),
                          self.__raw_buff)

    def show(self):
        print self.format

    def get_raw(self):
        return self.format.get_value_buff()

    def set_cm(self, cm):
        self.__CM = cm


class InnerClassesAttribute(BasicAttribute):
    def __init__(self, class_manager, buff):
        self.__CM = class_manager

        super(InnerClassesAttribute, self).__init__()
        # u2 attribute_name_index;
        # u4 attribute_length

        # u2 number_of_classes;
        self.number_of_classes = SV('>H', buff.read(2))

        # {  u2 inner_class_info_index;
        #     u2 outer_class_info_index;
        #     u2 inner_name_index;
        #     u2 inner_class_access_flags;
        # } classes[number_of_classes];
        self.__classes = []

        for i in range(0, self.number_of_classes.get_value()):
            self.__classes.append(InnerClassesDesc(self.__CM, buff))

    def get_classes(self):
        return self.__classes

    def show(self):
        print self.number_of_classes
        for i in self.__classes:
            i.show()

    def set_cm(self, cm):
        self.__CM = cm
        for i in self.__classes:
            i.set_cm(cm)

    def get_raw(self):
        return self.number_of_classes.get_value_buff() + \
               ''.join(x.get_raw() for x in self.__classes)


class ConstantValueAttribute(BasicAttribute):
    def __init__(self, class_manager, buff):
        self.__CM = class_manager

        super(ConstantValueAttribute, self).__init__()
        # u2 attribute_name_index;
        # u4 attribute_length;

        # u2 constantvalue_index;
        self.constantvalue_index = SV('>H', buff.read(2))

    def show(self):
        print self.constantvalue_index

    def set_cm(self, cm):
        self.__CM = cm

    def get_raw(self):
        return self.constantvalue_index.get_value_buff()


class EnclosingMethodAttribute(BasicAttribute):
    def __init__(self, class_manager, buff):
        ENCLOSING_METHOD_FORMAT = ['>HH', "class_index method_index"]

        self.__CM = class_manager

        super(EnclosingMethodAttribute, self).__init__()
        # u2 attribute_name_index;
        # u4 attribute_length;

        # u2 class_index
        # u2 method_index;

        self.__raw_buff = buff.read(calcsize(ENCLOSING_METHOD_FORMAT[0]))
        self.format = SVs(ENCLOSING_METHOD_FORMAT[0], namedtuple("EnclosingMethodFormat", ENCLOSING_METHOD_FORMAT[1]),
                          self.__raw_buff)

    def show(self):
        print self.format

    def set_cm(self, cm):
        self.__CM = cm

    def get_raw(self):
        return self.format.get_value_buff()


ATTRIBUTE_INFO_DESCR = {
    "Code": CodeAttribute,
    "Deprecated": DeprecatedAttribute,
    "SourceFile": SourceFileAttribute,
    "Exceptions": ExceptionsAttribute,
    "LineNumberTable": LineNumberTableAttribute,
    "LocalVariableTable": LocalVariableTableAttribute,
    "LocalVariableTypeTable": LocalVariableTypeTableAttribute,
    "StackMapTable": StackMapTableAttribute,
    "InnerClasses": InnerClassesAttribute,
    "ConstantValue": ConstantValueAttribute,
    "EnclosingMethod": EnclosingMethodAttribute,
    "Signature": SignatureAttribute,
    "Synthetic": SyntheticAttribute,
    "SourceDebugExtension": SourceDebugExtensionAttribute,
    "RuntimeVisibleAnnotations": RuntimeVisibleAnnotationsAttribute,
    "RuntimeInvisibleAnnotations": RuntimeInvisibleAnnotationsAttribute,
    "RuntimeVisibleParameterAnnotations": RuntimeVisibleParameterAnnotationsAttribute,
    "RuntimeInvisibleParameterAnnotations": RuntimeInvisibleParameterAnnotationsAttribute,
    "AnnotationDefault": AnnotationDefaultAttribute,
}


class AttributeInfo:
    """AttributeInfo manages each attribute info (Code, SourceFile ....)"""

    def __init__(self, class_manager, buff):
        self.__CM = class_manager
        self.__raw_buff = buff.read(calcsize(ATTRIBUTE_INFO[0]))

        self.format = SVs(ATTRIBUTE_INFO[0], ATTRIBUTE_INFO[1], self.__raw_buff)
        self.__name = self.__CM.get_string(self.format.get_value().attribute_name_index)

        try:
            self._info = ATTRIBUTE_INFO_DESCR[self.__name](self.__CM, buff)
        except KeyError, ke:
            bytecode.Exit("AttributeInfo %s doesn't exit" % self.__name)

    def get_item(self):
        """Return the specific attribute info"""
        return self._info

    def get_name(self):
        """Return the name of the attribute"""
        return self.__name

    def get_raw(self):
        v1 = self.format.get_value().attribute_length
        v2 = len(self._info.get_raw())
        if v1 != v2:
            self.set_attribute_length(v2)

        return self.format.get_value_buff() + self._info.get_raw()

    def get_attribute_name_index(self):
        return self.format.get_value().attribute_name_index

    def set_attribute_name_index(self, value):
        self.format.set_value({"attribute_name_index": value})

    def set_attribute_length(self, value):
        self.format.set_value({"attribute_length": value})

    def get_attributes(self):
        return self.format

    def _fix_attributes(self, new_cm):
        self._info._fix_attributes(new_cm)

    def set_cm(self, cm):
        self.__CM = cm
        self._info.set_cm(cm)

    def show(self):
        print self.format, self.__name
        if self._info != None:
            self._info.show()

    def pretty_show(self, m_a):
        print self.format, self.__name
        if self._info != None:
            if isinstance(self._info, CodeAttribute):
                self._info.pretty_show(m_a)
            else:
                self._info.show()


class ClassManager:
    """ClassManager can be used by all classes to get more information"""

    def __init__(self, constant_pool, constant_pool_count):
        self.constant_pool = constant_pool
        self.constant_pool_count = constant_pool_count

        self.__this_class = None

    def get_value(self, idx):
        name = self.get_item(idx[0]).get_name()
        if name == "CONSTANT_Integer":
            return [name, self.get_item(idx[0]).get_format().get_value().bytes]
        elif name == "CONSTANT_String":
            return [name, self.get_string(self.get_item(idx[0]).get_format().get_value().string_index)]
        elif name == "CONSTANT_Class":
            return [name, self.get_class(idx[0])]
        elif name == "CONSTANT_Fieldref":
            return [name, self.get_field(idx[0])]
        elif name == "CONSTANT_Float":
            return [name, self.get_item(idx[0]).get_format().get_value().bytes]

        bytecode.Exit("get_value not yet implemented for %s" % name)

    def get_item(self, idx):
        return self.constant_pool[idx - 1]

    def get_interface(self, idx):
        if self.get_item(idx).get_name() != "CONSTANT_InterfaceMethodref":
            return []

        class_idx = self.get_item(idx).get_class_index()
        name_and_type_idx = self.get_item(idx).get_name_and_type_index()

        return [self.get_string(self.get_item(class_idx).get_name_index()),
                self.get_string(self.get_item(name_and_type_idx).get_name_index()),
                self.get_string(self.get_item(name_and_type_idx).get_descriptor_index())
        ]

    def get_interface_index(self, class_name, name, descriptor):
        raise ("ooo")

    def get_method(self, idx):
        if self.get_item(idx).get_name() != "CONSTANT_Methodref":
            return []

        class_idx = self.get_item(idx).get_class_index()
        name_and_type_idx = self.get_item(idx).get_name_and_type_index()

        return [self.get_string(self.get_item(class_idx).get_name_index()),
                self.get_string(self.get_item(name_and_type_idx).get_name_index()),
                self.get_string(self.get_item(name_and_type_idx).get_descriptor_index())
        ]

    def get_method_index(self, class_name, name, descriptor):
        idx = 1
        for i in self.constant_pool:
            res = self.get_method(idx)
            if res != []:
                m_class_name, m_name, m_descriptor = res
                if m_class_name == class_name and m_name == name and m_descriptor == descriptor:
                    return idx
            idx += 1

        return -1

    def get_field(self, idx):
        if self.get_item(idx).get_name() != "CONSTANT_Fieldref":
            return []

        class_idx = self.get_item(idx).get_class_index()
        name_and_type_idx = self.get_item(idx).get_name_and_type_index()

        return [self.get_string(self.get_item(class_idx).get_name_index()),
                self.get_string(self.get_item(name_and_type_idx).get_name_index()),
                self.get_string(self.get_item(name_and_type_idx).get_descriptor_index())
        ]

    def get_field_index(self, name, descriptor):
        idx = 1
        for i in self.constant_pool:
            res = self.get_field(idx)
            if res != []:
                _, m_name, m_descriptor = res
                if m_name == name and m_descriptor == descriptor:
                    return idx
            idx += 1

    def get_class(self, idx):
        if self.get_item(idx).get_name() != "CONSTANT_Class":
            return []

        return [self.get_string(self.get_item(idx).get_name_index())]

    def get_array_type(self, idx):
        return ARRAY_TYPE[idx[0]]

    def get_string_index(self, name):
        idx = 1
        for i in self.constant_pool:
            if i.get_name() == "CONSTANT_Utf8":
                if i.get_bytes() == name:
                    return idx
            idx += 1
        return -1

    def get_integer_index(self, value):
        idx = 1
        for i in self.constant_pool:
            if i.get_name() == "CONSTANT_Integer":
                if i.get_format().get_value().bytes == value:
                    return idx
            idx += 1
        return -1

    def get_cstring_index(self, value):
        idx = 1
        for i in self.constant_pool:
            if i.get_name() == "CONSTANT_String":
                if self.get_string(i.get_format().get_value().string_index) == value:
                    return idx
            idx += 1
        return -1

    def get_name_and_type_index(self, name_method_index, descriptor_method_index):
        idx = 1
        for i in self.constant_pool:
            if i.get_name() == "CONSTANT_NameAndType":
                value = i.get_format().get_value()
                if value.name_index == name_method_index and value.descriptor_index == descriptor_method_index:
                    return idx
            idx += 1
        return -1

    def get_class_by_index(self, name_index):
        idx = 1
        for i in self.constant_pool:
            if i.get_name() == "CONSTANT_Class":
                value = i.get_format().get_value()
                if value.name_index == name_index:
                    return idx
            idx += 1
        return -1

    def get_method_ref_index(self, new_class_index, new_name_and_type_index):
        idx = 1
        for i in self.constant_pool:
            if i.get_name() == "CONSTANT_Methodref":
                value = i.get_format().get_value()
                if value.class_index == new_class_index and value.name_and_type_index == new_name_and_type_index:
                    return idx
            idx += 1
        return -1

    def get_field_ref_index(self, new_class_index, new_name_and_type_index):
        idx = 1
        for i in self.constant_pool:
            if i.get_name() == "CONSTANT_Fieldref":
                value = i.get_format().get_value()
                if value.class_index == new_class_index and value.name_and_type_index == new_name_and_type_index:
                    return idx
            idx += 1
        return -1

    def get_class_index(self, method_name):
        idx = 1
        for i in self.constant_pool:
            res = self.get_method(idx)
            if res != []:
                _, name, _ = res
                if name == method_name:
                    return i.get_class_index()
            idx += 1
        return -1

    def get_class_index2(self, class_name):
        idx = 1
        for i in self.constant_pool:
            res = self.get_class(idx)
            if res != []:
                name = res[0]
                if name == class_name:
                    return idx
            idx += 1
        return -1

    def get_used_fields(self):
        l = []
        for i in self.constant_pool:
            if i.get_name() == "CONSTANT_Fieldref":
                l.append(i)
        return l

    def get_used_methods(self):
        l = []
        for i in self.constant_pool:
            if i.get_name() == "CONSTANT_Methodref":
                l.append(i)
        return l

    def get_string(self, idx):
        if self.constant_pool[idx - 1].get_name() == "CONSTANT_Utf8":
            return self.constant_pool[idx - 1].get_bytes()
        return None

    def set_string(self, idx, name):
        if self.constant_pool[idx - 1].get_name() == "CONSTANT_Utf8":
            self.constant_pool[idx - 1].set_bytes(name)
        else:
            bytecode.Exit("invalid index %d to set string %s" % (idx, name))

    def add_string(self, name):
        name_index = self.get_string_index(name)
        if name_index != -1:
            return name_index

        tag_value = INVERT_CONSTANT_INFO["CONSTANT_Utf8"]
        buff = pack(CONSTANT_INFO[tag_value][1], tag_value, len(name)) + pack(">%ss" % len(name), name)
        ci = CONSTANT_INFO[tag_value][-1](self, bytecode.BuffHandle(buff))

        self.constant_pool.append(ci)
        self.constant_pool_count.set_value(self.constant_pool_count.get_value() + 1)

        return self.constant_pool_count.get_value() - 1

    def set_this_class(self, this_class):
        self.__this_class = this_class

    def get_this_class(self):
        return self.__this_class.get_value()

    def get_this_class_name(self):
        return self.get_class(self.__this_class.get_value())[0]

    def add_constant_pool(self, elem):
        self.constant_pool.append(elem)
        self.constant_pool_count.set_value(self.constant_pool_count.get_value() + 1)

    def get_constant_pool_count(self):
        return self.constant_pool_count.get_value()

    def create_class(self, name):
        class_name_index = self.add_string(name)
        return self._create_class(class_name_index)

    def _create_class(self, class_name_index):
        class_index = self.get_class_by_index(class_name_index)
        if class_index == -1:
            new_class = CreateClass(self, class_name_index)
            self.add_constant_pool(Class(self, bytecode.BuffHandle(new_class.get_raw())))
            class_index = self.get_constant_pool_count() - 1
        return class_index

    def create_name_and_type(self, name, desc):
        name_index = self.add_string(name)
        descriptor_index = self.add_string(desc)

        return self._create_name_and_type(name_index, descriptor_index)

    def create_name_and_type_by_index(self, name_method_index, descriptor_method_index):
        return self._create_name_and_type(name_method_index, descriptor_method_index)

    def _create_name_and_type(self, name_method_index, descriptor_method_index):
        name_and_type_index = self.get_name_and_type_index(name_method_index, descriptor_method_index)
        if name_and_type_index == -1:
            new_nat = CreateNameAndType(self, name_method_index, descriptor_method_index)
            self.add_constant_pool(NameAndType(self, bytecode.BuffHandle(new_nat.get_raw())))
            name_and_type_index = self.get_constant_pool_count() - 1
        return name_and_type_index

    def create_method_ref(self, new_class_index, new_name_and_type_index):
        new_mr_index = self.get_method_ref_index(new_class_index, new_name_and_type_index)
        if new_mr_index == -1:
            new_mr = CreateMethodRef(self, new_class_index, new_name_and_type_index)
            self.add_constant_pool(MethodRef(self, bytecode.BuffHandle(new_mr.get_raw())))
            new_mr_index = self.get_constant_pool_count() - 1
        return new_mr_index

    def create_field_ref(self, new_class_index, new_name_and_type_index):
        new_fr_index = self.get_field_ref_index(new_class_index, new_name_and_type_index)
        if new_fr_index == -1:
            new_fr = CreateFieldRef(self, new_class_index, new_name_and_type_index)
            self.add_constant_pool(FieldRef(self, bytecode.BuffHandle(new_fr.get_raw())))
            new_fr_index = self.get_constant_pool_count() - 1
        return new_fr_index

    def create_integer(self, value):
        new_int_index = self.get_integer_index(value)
        if new_int_index == -1:
            new_int = CreateInteger(value)
            self.add_constant_pool(Integer(self, bytecode.BuffHandle(new_int.get_raw())))
            new_int_index = self.get_constant_pool_count() - 1

        return new_int_index

    def create_string(self, value):
        new_string_index = self.get_cstring_index(value)
        if new_string_index == -1:
            new_string = CreateString(self, value)
            self.add_constant_pool(String(self, bytecode.BuffHandle(new_string.get_raw())))
            new_string_index = self.get_constant_pool_count() - 1
        return new_string_index


class JVMFormat(bytecode._Bytecode):
    """
        An object which is the main class to handle properly a class file.
        Exported fields : magic, minor_version, major_version, constant_pool_count, access_flags, this_class, super_class, interfaces_count, fields_count, methods_count, attributes_count
    """

    def __init__(self, buff):
        """
            @param buff : the buffer which represents the open file
        """
        super(JVMFormat, self).__init__(buff)

        self._load_class()

    def _load_class(self):
        # u4 magic;
        # u2 minor_version;
        # u2 major_version;
        self.magic = SV('>L', self.read(4))
        self.minor_version = SV('>H', self.read(2))
        self.major_version = SV('>H', self.read(2))

        # u2 constant_pool_count;
        self.constant_pool_count = SV('>H', self.read(2))

        #  cp_info constant_pool[constant_pool_count-1];
        self.constant_pool = []
        self.__CM = ClassManager(self.constant_pool, self.constant_pool_count)

        i = 1
        while (i < self.constant_pool_count.get_value()):
            tag = SV('>B', self.read_b(1))

            if tag.get_value() not in CONSTANT_INFO:
                bytecode.Exit("tag %d not in CONSTANT_INFO" % tag.get_value())

            ci = CONSTANT_INFO[tag.get_value()][-1](self.__CM, self)
            self.constant_pool.append(ci)

            i = i + 1
            # CONSTANT_Long or CONSTANT_Double
            #        If a CONSTANT_Long_info or CONSTANT_Double_info structure is the item
            #        in the constant_pool table at index n, then the next usable item in the pool is
            #        located at index n + 2. The constant_pool index n + 1 must be valid but is
            #        considered unusable.
            if tag.get_value() == 5 or tag.get_value() == 6:
                self.constant_pool.append(EmptyConstant())
                i = i + 1

        # u2 access_flags;
        # u2 this_class;
        # u2 super_class;
        self.access_flags = SV('>H', self.read(2))
        self.this_class = SV('>H', self.read(2))
        self.super_class = SV('>H', self.read(2))

        self.__CM.set_this_class(self.this_class)

        # u2 interfaces_count;
        self.interfaces_count = SV('>H', self.read(2))

        # u2 interfaces[interfaces_count];
        self.interfaces = []
        for i in range(0, self.interfaces_count.get_value()):
            tag = SV('>H', self.read(2))
            self.interfaces.append(tag)


        # u2 fields_count;
        self.fields_count = SV('>H', self.read(2))

        # field_info fields[fields_count];
        self.fields = []
        for i in range(0, self.fields_count.get_value()):
            fi = FieldInfo(self.__CM, self)
            self.fields.append(fi)

        # u2 methods_count;
        self.methods_count = SV('>H', self.read(2))

        # method_info methods[methods_count];
        self.methods = []
        for i in range(0, self.methods_count.get_value()):
            mi = MethodInfo(self.__CM, self)
            self.methods.append(mi)

        # u2 attributes_count;
        self.attributes_count = SV('>H', self.read(2))

        # attribute_info attributes[attributes_count];
        self.__attributes = []
        for i in range(0, self.attributes_count.get_value()):
            ai = AttributeInfo(self.__CM, self)
            self.__attributes.append(ai)

    def get_class(self, class_name):
        """
            Verify the name of the class

            @param class_name : the name of the class

            @rtype : True if the class name is valid, otherwise it's False
        """
        x = self.__CM.get_this_class_name() == class_name
        if x == True:
            return x

        return self.__CM.get_this_class_name() == class_name.replace(".", "/")

    def get_classes_names(self):
        """
            Return the names of classes
        """
        return [self.__CM.get_this_class_name()]

    def get_name(self):
        """

        """
        return self.__CM.get_this_class_name()

    def get_classes(self):
        """

        """
        return [self]

    def get_field(self, name):
        """
            Return into a list all fields which corresponds to the regexp

            @param name : the name of the field (a regexp)
        """
        prog = re.compile(name)
        fields = []
        for i in self.fields:
            if prog.match(i.get_name()):
                fields.append(i)
        return fields

    def get_method_descriptor(self, class_name, method_name, descriptor):
        """
            Return the specific method

            @param class_name : the class name of the method
            @param method_name : the name of the method
            @param descriptor : the descriptor of the method

            @rtype: L{MethodInfo}
        """
        # FIXME : handle multiple class name ?
        if class_name != None:
            if class_name != self.__CM.get_this_class_name():
                return None

        for i in self.methods:
            if method_name == i.get_name() and descriptor == i.get_descriptor():
                return i

        return None

    def get_field_descriptor(self, class_name, field_name, descriptor):
        """
            Return the specific field

            @param class_name : the class name of the field
            @param field_name : the name of the field
            @param descriptor : the descriptor of the field

            @rtype: L{FieldInfo}
        """
        # FIXME : handle multiple class name ?
        if class_name != None:
            if class_name != self.__CM.get_this_class_name():
                return None

        for i in self.fields:
            if field_name == i.get_name() and descriptor == i.get_descriptor():
                return i
        return None

    def get_method(self, name):
        """Return into a list all methods which corresponds to the regexp

            @param name : the name of the method (a regexp)
        """
        prog = re.compile(name)
        methods = []
        for i in self.methods:
            if prog.match(i.get_name()):
                methods.append(i)
        return methods

    def get_all_fields(self):
        return self.fields

    def get_fields(self):
        """Return all objects fields"""
        return self.fields

    def get_methods(self):
        """Return all objects methods"""
        return self.methods

    def get_constant_pool(self):
        """Return the constant pool list"""
        return self.constant_pool

    def get_strings(self):
        """Return all strings into the class"""
        l = []
        for i in self.constant_pool:
            if i.get_name() == "CONSTANT_Utf8":
                l.append(i.get_bytes())
        return l

    def get_class_manager(self):
        """
            Return directly the class manager

            @rtype : L{ClassManager}
        """
        return self.__CM

    def set_used_field(self, old, new):
        """
            Change the description of a field

            @param old : a list of string which contained the original class name, the original field name and the original descriptor
            @param new : a list of string which contained the new class name, the new field name and the new descriptor
        """
        used_fields = self.__CM.get_used_fields()
        for i in used_fields:
            class_idx = i.format.get_value().class_index
            name_and_type_idx = i.format.get_value().name_and_type_index
            class_name = self.__CM.get_string(self.__CM.get_item(class_idx).get_name_index())
            field_name = self.__CM.get_string(self.__CM.get_item(name_and_type_idx).get_name_index())
            descriptor = self.__CM.get_string(self.__CM.get_item(name_and_type_idx).get_descriptor_index())

            if old[0] == class_name and old[1] == field_name and old[2] == descriptor:
            #              print "SET USED FIELD", class_name, method_name, descriptor

                self.__CM.set_string(self.__CM.get_item(class_idx).get_name_index(), new[0])
                self.__CM.set_string(self.__CM.get_item(name_and_type_idx).get_name_index(), new[1])
                self.__CM.set_string(self.__CM.get_item(name_and_type_idx).get_descriptor_index(), new[2])

    def set_used_method(self, old, new):
        """
            Change the description of a method
            @param old : a list of string which contained the original class name, the original method name and the original descriptor
            @param new : a list of string which contained the new class name, the new method name and the new descriptor
        """
        used_methods = self.__CM.get_used_methods()
        for i in used_methods:
            class_idx = i.format.get_value().class_index
            name_and_type_idx = i.format.get_value().name_and_type_index
            class_name = self.__CM.get_string(self.__CM.get_item(class_idx).get_name_index())
            method_name = self.__CM.get_string(self.__CM.get_item(name_and_type_idx).get_name_index())
            descriptor = self.__CM.get_string(self.__CM.get_item(name_and_type_idx).get_descriptor_index())

            if old[0] == class_name and old[1] == method_name and old[2] == descriptor:
            #                print "SET USED METHOD", class_name, method_name, descriptor

                self.__CM.set_string(self.__CM.get_item(class_idx).get_name_index(), new[0])
                self.__CM.set_string(self.__CM.get_item(name_and_type_idx).get_name_index(), new[1])
                self.__CM.set_string(self.__CM.get_item(name_and_type_idx).get_descriptor_index(), new[2])


    def show(self):
        """
            Show the .class format into a human readable format
        """
        bytecode._Print("MAGIC", self.magic.get_value())
        bytecode._Print("MINOR VERSION", self.minor_version.get_value())
        bytecode._Print("MAJOR VERSION", self.major_version.get_value())
        bytecode._Print("CONSTANT POOL COUNT", self.constant_pool_count.get_value())

        nb = 0
        for i in self.constant_pool:
            print nb,
            i.show()
            nb += 1

        bytecode._Print("ACCESS FLAGS", self.access_flags.get_value())
        bytecode._Print("THIS CLASS", self.this_class.get_value())
        bytecode._Print("SUPER CLASS", self.super_class.get_value())

        bytecode._Print("INTERFACE COUNT", self.interfaces_count.get_value())
        nb = 0
        for i in self.interfaces:
            print nb,
            print i

        bytecode._Print("FIELDS COUNT", self.fields_count.get_value())
        nb = 0
        for i in self.fields:
            print nb,
            i.show()
            nb += 1

        bytecode._Print("METHODS COUNT", self.methods_count.get_value())
        nb = 0
        for i in self.methods:
            print nb,
            i.show()
            nb += 1

        bytecode._Print("ATTRIBUTES COUNT", self.attributes_count.get_value())
        nb = 0
        for i in self.__attributes:
            print nb,
            i.show()
            nb += 1

    def pretty_show(self, vm_a):
        """
            Show the .class format into a human readable format
        """
        bytecode._Print("MAGIC", self.magic.get_value())
        bytecode._Print("MINOR VERSION", self.minor_version.get_value())
        bytecode._Print("MAJOR VERSION", self.major_version.get_value())
        bytecode._Print("CONSTANT POOL COUNT", self.constant_pool_count.get_value())

        nb = 0
        for i in self.constant_pool:
            print nb,
            i.show()
            nb += 1

        bytecode._Print("ACCESS FLAGS", self.access_flags.get_value())
        bytecode._Print("THIS CLASS", self.this_class.get_value())
        bytecode._Print("SUPER CLASS", self.super_class.get_value())

        bytecode._Print("INTERFACE COUNT", self.interfaces_count.get_value())
        nb = 0
        for i in self.interfaces:
            print nb,
            i.show()

        bytecode._Print("FIELDS COUNT", self.fields_count.get_value())
        nb = 0
        for i in self.fields:
            print nb,
            i.show()
            nb += 1

        bytecode._Print("METHODS COUNT", self.methods_count.get_value())
        nb = 0
        for i in self.methods:
            print nb,
            i.pretty_show(vm_a)
            nb += 1

        bytecode._Print("ATTRIBUTES COUNT", self.attributes_count.get_value())
        nb = 0
        for i in self.__attributes:
            print nb,
            i.show()

    def insert_string(self, value):
        """Insert a string into the constant pool list (Constant_Utf8)

            @param value : the new string
        """
        self.__CM.add_string(value)

    def insert_field(self, class_name, name, descriptor):
        """
            Insert a field into the class

            @param class_name : the class of the field
            @param name : the name of the field
            @param descriptor : a list with the access_flag and the descriptor ( [ "ACC_PUBLIC", "I" ] )
        """
        new_field = CreateFieldInfo(self.__CM, name, descriptor)

        new_field = FieldInfo(self.__CM, bytecode.BuffHandle(new_field.get_raw()))

        self.fields.append(new_field)
        self.fields_count.set_value(self.fields_count.get_value() + 1)

        # Add a FieldRef and a NameAndType
        name_and_type_index = self.__CM.create_name_and_type_by_index(new_field.get_name_index(),
                                                                      new_field.get_descriptor_index())
        self.__CM.create_field_ref(self.__CM.get_this_class(), name_and_type_index)

    def insert_craft_method(self, name, proto, codes):
        """
            Insert a craft method into the class

            @param name : the name of the new method
            @param proto : a list which describe the method ( [ ACCESS_FLAGS, RETURN_TYPE, ARGUMENTS ], ie : [ "ACC_PUBLIC", "[B", "[B" ] )
            @param codes : a list which represents the code into a human readable format ( [ "aconst_null" ], [ "areturn" ] ] )
        """
        # Create new method
        new_method = CreateMethodInfo(self.__CM, name, proto, codes)

        # Insert the method by casting it directly into a MethodInfo with the raw buffer
        self._insert_basic_method(MethodInfo(self.__CM, bytecode.BuffHandle(new_method.get_raw())))

    def insert_direct_method(self, name, ref_method):
        """
            Insert a direct method (MethodInfo object) into the class

            @param name : the name of the new method
            @param ref_method : the MethodInfo Object
        """
        if ref_method == None:
            return

        # Change the name_index
        name_index = self.__CM.get_string_index(name)
        if name_index != -1:
            bytecode.Exit("method %s already exits" % name)

        name_index = self.__CM.add_string(name)
        ref_method.set_name_index(name_index)

        # Change the descriptor_index
        descriptor_index = self.__CM.get_string_index(ref_method.get_descriptor())
        if descriptor_index == -1:
            descriptor_index = self.__CM.add_string(ref_method.get_descriptor())
        ref_method.set_descriptor_index(descriptor_index)

        # Change attributes name index
        self._fix_attributes_external(ref_method)

        # Change internal index
        self._fix_attributes_internal(ref_method)

        # Insert the method
        self._insert_basic_method(ref_method)

    def _fix_attributes_external(self, ref_method):
        for i in ref_method.get_attributes():
            attribute_name_index = self.__CM.add_string(i.get_name())

            i.set_attribute_name_index(attribute_name_index)

            self._fix_attributes_external(i.get_item())

    def _fix_attributes_internal(self, ref_method):
        for i in ref_method.get_attributes():
            attribute_name_index = self.__CM.add_string(i.get_name())

            i._fix_attributes(self.__CM)

            i.set_attribute_name_index(attribute_name_index)

    def _insert_basic_method(self, ref_method):
        # Add a MethodRef and a NameAndType
        name_and_type_index = self.__CM.create_name_and_type_by_index(ref_method.get_name_index(),
                                                                      ref_method.get_descriptor_index())

        self.__CM.create_method_ref(self.__CM.get_this_class(), name_and_type_index)

        # Change the class manager
        ref_method.set_cm(self.__CM)

        # Insert libraries/constants dependances
        methods = ref_method._patch_bytecodes()

        # FIXME : insert needed fields + methods
        prog = re.compile("^java*")
        for i in methods:
            if prog.match(i[0]) == None:
                bytecode.Exit("ooooops")


        #ref_method.show()

        # Insert the method
        self.methods.append(ref_method)
        self.methods_count.set_value(self.methods_count.get_value() + 1)

    def _get_raw(self):
        # u4 magic;
        # u2 minor_version;
        # u2 major_version;
        buff = self.magic.get_value_buff()
        buff += self.minor_version.get_value_buff()
        buff += self.major_version.get_value_buff()

        # u2 constant_pool_count;
        buff += self.constant_pool_count.get_value_buff()

        #  cp_info constant_pool[constant_pool_count-1];
        for i in self.constant_pool:
            buff += i.get_raw()

        # u2 access_flags;
        # u2 this_class;
        # u2 super_class;
        buff += self.access_flags.get_value_buff()
        buff += self.this_class.get_value_buff()
        buff += self.super_class.get_value_buff()

        # u2 interfaces_count;
        buff += self.interfaces_count.get_value_buff()

        # u2 interfaces[interfaces_count];
        for i in self.interfaces:
            buff += i.get_value_buff()

        # u2 fields_count;
        buff += self.fields_count.get_value_buff()

        # field_info fields[fields_count];
        for i in self.fields:
            buff += i.get_raw()

        # u2 methods_count;
        buff += self.methods_count.get_value_buff()

        # method_info methods[methods_count];
        for i in self.methods:
            buff += i.get_raw()

        # u2 attributes_count;
        buff += self.attributes_count.get_value_buff()

        # attribute_info attributes[attributes_count];
        for i in self.__attributes:
            buff += i.get_raw()

        return buff

    def save(self):
        """
            Return the class (with the modifications) into raw format

            @rtype: string
        """
        return self._get_raw()

    def set_vmanalysis(self, vmanalysis):
        pass

    def get_generator(self):
        from CheckProtect.androguard.core.bytecodes import jvm_generate

        return jvm_generate.JVMGenerate

    def get_INTEGER_INSTRUCTIONS(self):
        return INTEGER_INSTRUCTIONS

    def get_type(self):
        return "JVM"
